Upload a file using Angular 6 to Web Api C# - c#

I have Angular CLI application and Dot net core 2.0 Web API. which I need to upload the file from Angular to Web API. from Web API to Server. When I use Http its working fine. When using HttpClient, it's not working.
Here is my component.ts code:
fileChange(event, grdvalue) {
debugger;
let fileList: FileList = event.target.files;
if (fileList.length > 0) {
let file: File = fileList[0];
const formData: FormData = new FormData();
let GridName = grdvalue;
formData.append('file', file, file.name);
formData.append('Id', this.userId);
formData.append('GridValue', GridName)
this.myService.PostFileToAzure(formData).subscribe(details => {
debugger;
},
(error) => {
debugger;
})
}
}
here is My Service Code:
PostFileToAzure(form) {
debugger;
var body = JSON.stringify(form);
return this.http.post(this.baseApiURL + '/Interpretation/InterpreterFileUpload', form);
}
Here is my Web API code:
[HttpPost("InterpreterFileUpload")]
public async Task<IActionResult> InterpreterFileUpload()
{
try
{
var file = Request.Form.Files[0];
HttpRequest formData = HttpContext.Request;
}
}
How to do send the file using HttpClient From Angular to Web API. Am getting an error in web API like 'Incorrect Content-Type: application/json'

At angular site use this code
file: any;
onSelectFile($event, file) {
this.file = file;
}
uploadImage() {
if (this.file.length === 0) {
return;
}
const formData = new FormData();
for (let file of this.file)
formData.append(file.name, file);
const uploadReq = new HttpRequest('POST', `api/FileUpload`, formData, {
reportProgress: true,
});
this.http.request(uploadReq).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) {
this.progress = Math.round(100 * event.loaded / event.total);
}
});
}
here onSelectFile should be called on input like this
<input #file type='file' multiple (change)="onSelectFile($event, file.files)">
And at your asp.net site use this code
[Produces("application/json")]
[Route("api/[controller]")]
public class FileUploadController : Controller
{
private IHostingEnvironment _hostingEnvironment;
public FileUploadController(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
[HttpPost, DisableRequestSizeLimit]
public ObjectResult UploadFile()
{
try
{
var file = Request.Form.Files[0];
string folderName = "Upload";
string webRootPath = _hostingEnvironment.WebRootPath;
string newPath = Path.Combine(webRootPath, folderName);
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
string fileName = "";
if (file.Length > 0)
{
fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
string fullPath = Path.Combine(newPath, fileName);
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}
}
return Ok(fileName);
}
catch (System.Exception ex)
{
return BadRequest(ex.Message);
}
}
}
Thanks

https://github.com/BhadraAnirban/angular_file_upload_net_core
The process is to send the base64 string from Angular using POST call in the FormBody and at .net core convert the string to byte.
Note - FormData will not work in AWS Lambda properly, it will corrupt the file. So this is a better approach to send mail or upload file in AWS as well.
HTML -
<form class="row">
<input id="{{id}}" type="file" (change)="FileSelected($event.target.files);">
</form>
<div id="hidden_upload_item" style="display: none;"></div>
Typescript -
FileSelected(files){
this.fileData = <File>files[0];
this.FileName = this.fileData.name;
let reader = new FileReader();
var selectedFile = <File>files[0];
reader.onload = function (readerEvt: any) {
var arrayBuffer = readerEvt.target.result.toString().split('base64,')[1];
document.querySelector('#hidden_upload_item').innerHTML = arrayBuffer;
this.Proceed();
}.bind(this);
reader.readAsDataURL(selectedFile);
}
Proceed()
{
var item = document.querySelector('#hidden_upload_item').innerHTML;
let formdata = new UploadFile();
formdata.data = item;
formdata.name = this.FileName;
this.UploadDocument(formdata)
.subscribe(event => {
// Perform other operations
}, err => {
this.InProgress = false;
});
}
UploadDocument(formData){
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post('/api/document/uploaddocument', formData, httpOptions);
}
.net Core -
[HttpPost("uploaddocument"), DisableRequestSizeLimit]
public IActionResult UploadDocument([FromBody] FileModel fileModel)
{
try
{
var value = fileModel.Data;
var byteArray = Convert.FromBase64String(value);
var fileExtension = Path.GetExtension(fileModel.Name);
var fileName = fileModel.Name;
/// Now save in Database or AWS
}
return Ok();
}
catch (Exception e)
{
throw e;
}
}
public class FileModel
{
public string Data { get; set; }
public string Name { get; set; }
}

I had used the solution of #Elon Musk but Request.Form.Files[0]gives me the Evaluation timeout exception, so to handle it, I have added the Iformfile parameter in Actionmethod in .net side
public IActionResult UploadFile(IFormFile formfile)

Related

Azure Function httptrigger working from Postman but not HTTPClient

I have a working ASP.NET Core Web API that I'm currently refactoring to an Azure Function. An image is uploaded in the front end, sent to the Azure Function as a POST request where it is uploaded to Azure Blob Storage. Right now my Azure Function works completely fine when testing with Postman but does nothing when I actually use my client application. A postman request will hit my breakpoint in the azure function but a c# httpclient request does not.
FRONT END CODE
public partial class ImageUpload
{
[Inject]
public HttpClient HttpClient { get; set; }
public string ImgUrl { get; set; }
private async Task HandleSelected(InputFileChangeEventArgs e)
{
var imageFile = e.File;
if (imageFile == null)
return;
var resizedFile = await imageFile.RequestImageFileAsync("image/png", 300, 500);
using (var ms = resizedFile.OpenReadStream(resizedFile.Size))
{
var content = new MultipartFormDataContent();
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
content.Add(new StreamContent(ms, Convert.ToInt32(resizedFile.Size)), "image", imageFile.Name);
var response = await HttpClient.PostAsync("url/to/my/azure/function/api", content);
ImgUrl = await response.Content.ReadAsStringAsync();
}
}
}
Azure Function API
public static class Upload
{
[FunctionName("Upload")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
ILogger log)
{
var formCollection = await req.ReadFormAsync();
var file = formCollection.Files.First();
if (file.Length > 0)
{
var container = new BlobContainerClient("connection string to blob storage", "upload-container");
var createResponse = await container.CreateIfNotExistsAsync();
if (createResponse != null && createResponse.GetRawResponse().Status == 201)
await container.SetAccessPolicyAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
var blob = container.GetBlobClient(file.FileName);
await blob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots);
using (var fileStream = file.OpenReadStream())
{
await blob.UploadAsync(fileStream, new BlobHttpHeaders { ContentType = file.ContentType });
}
return (ActionResult)new OkObjectResult(blob.Uri.ToString());
}
return new BadRequestObjectResult("Error");
}
}
Can anyone point me in the right direction of what I'm messing up?
Add this setting to the local.settings.json
"Host": {
"LocalHttpPort": 7071,
"CORS": "*"
}

How to upload file to an ASP.NET Core controller?

I have this client code on web-client to load some kind of file.
fileUploaded(files) {
files.forEach(async ifile => {
await axios.post('http://localhost:5000/api/upload', ifile)
.then(res => {
console.log(res)
}).catch(err => {
console.error(err);
});
});
}
My endpoint code looks like this:
[HttpPost("upload")]
public async Task<IActionResult> UploadFile([FromBody] IFormFile file)
{
var data = new byte[file.Length];
using (var bstream = file.OpenReadStream())
{
while (bstream.CanRead)
{
bstream.Read(data);
}
}
// etc
return Ok();
}
Parameter file is always null. How to deliver this file from the client the right way?
Instead of
UploadFile([FromBody] IFormFile file)
Use
UploadFile([FromForm] IFormFile file)
And
fileUploaded(files) {
files.forEach(async ifile => {
const formData = new FormData();
formData.append('file', ifile)
await axios.post('http://localhost:5000/api/upload', formData)
.then(res => {
console.log(res)
}).catch(err => {
console.error(err);
});
});
}
in the UploadFile method, just, do this
//if asp.net mvc
var file1 = System.Web.HttpContext.Current.Request.Files[0];
//if asp.net core
var file2 = Request.Form.Files[0];

Writing fulfillment webhook for Dialogflow in .NET C#

I am new to working with dialogflow and fairly new to .NET. I have been struggling for a while now to create my fulfillment webhook. I have got it to work with the node.js inline-editor but want to create my own WebhookController in .NET so I can make external API calls/db calls more easily. Here is what I have so far:
I have a really basic whats-app-like UI where a user can input some text which is appended to a chat window and then the javascript is pinged for the chatbot's response:
function userSubmit() {
var userInput = document.getElementById('user-input').value;
$.ajax({
type: "GET",
url: "/Home/CheckIntentAsync",
data: {
userInput: userInput
},
async: true,
contentType: "application/json",
success: function (data) {
var reply = data;
var botNode = document.createElement("div");
botNode.classList.add('chat');
botNode.classList.add('bot-chat');
botNode.innerHTML = reply; // <--- appends chat window with the reply from Dialogflow
chatWindow.appendChild(botNode);
chatWindow.scrollTop = chatWindow.scrollHeight;
console.log(data);
},
error: function () {
var reply = "I didn't quite catch that, can you rephrase? :/";
var botNode = document.createElement("div");
botNode.classList.add('chat');
botNode.classList.add('bot-chat');
botNode.innerHTML = reply;
chatWindow.appendChild(botNode);
}
});
The ajax call pings my HomeController class which connects to Dialogflow:
public class HomeController : Controller
{
private string sessionID = "XXX"; // my session ID
private string projectID = "XXX"; // my projectID
public ActionResult Index()
{
SetEnvironmentVariable();
return View();
}
private void SetEnvironmentVariable()
{
try
{
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "MY PATH TO SERVICE ACCOUNT PRIVATE KEY IS HERE");
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentException)
{
throw;
}
}
[HttpGet]
public async Task<JsonResult> CheckIntentAsync(string userInput)
{
var sessionClient = await SessionsClient.CreateAsync();
var sessionName = new SessionName(projectID, sessionID);
QueryInput queryInput = new QueryInput();
var queryText = new TextInput();
queryText.Text = userInput;
queryText.LanguageCode = "en";
queryInput.Text = queryText;
// Make the request
DetectIntentResponse response = await sessionClient.DetectIntentAsync(sessionName, queryInput);
var reply = response.QueryResult;
return Json(reply, JsonRequestBehavior.AllowGet);
}
}
So far all of the above works a charm with the inline-editor in Dialogflow. I now am creating my webhook fulfilment in .NET and cannot get it to work. My API class looks like this:
public class WebhookController : ApiController
{
private static readonly JsonParser jsonParser =
new JsonParser(JsonParser.Settings.Default.WithIgnoreUnknownFields(true));
[HttpPost]
public async Task<HttpResponseMessage> Post()
{
WebhookRequest request;
using (var stream = await Request.Content.ReadAsStreamAsync())
{
using (var reader = new StreamReader(stream))
{
request = jsonParser.Parse<WebhookRequest>(reader);
}
}
// Simply sets the fulfillment text to equal the name of the intent detected by Dialogflow
WebhookResponse webhookResponse = new WebhookResponse
{
FulfillmentText = request.QueryResult.Intent.DisplayName
};
HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(webhookResponse.ToString())
{
Headers = { ContentType = new MediaTypeHeaderValue("text/json") }
}
};
return httpResponse;
}
}
When I run this, I get in the dialogflow console's diagnostic info a 'DEADLINE_EXCEEDED' message however the webhook is doing so little I don't understand why this is?
"webhookStatus": {
"code": 4,
"message": "Webhook call failed. Error: DEADLINE_EXCEEDED."
}
I don't know if I'm supposed to perform some sort of authentication in the webhook as well as in my HomeController?
Some help would be greatly greatly appreciated!!!
Many thanks!
I was getting this same error when i enabled the webhook call from a follow up intent that wasn't mapped (to handler) in fulfillment inline editor.

Why doesn't this ASP.NET Core code work on remote host

I have an Angular web site that works on my local host. When I upload it to a remote host, it fails without an error. Just doesn't save any files.
I have searched the web for an answer. No joy.
This never returns an error on either the local Visual Studio 2019 or the remote.
Found the basic code on Microsoft site. Looked at a lot of angular sites
[Route("api/[controller]")]
[ApiController]
public class UploadController : ControllerBase
{
private IHostingEnvironment env;
public UploadController(IHostingEnvironment hostingEnvironment)
{
env = hostingEnvironment;
}
[HttpPost, DisableRequestSizeLimit]
public async Task<IActionResult> Upload()
{
try
{
var files = Request.Form.Files;
if (files.Count < 1)
{
return BadRequest();
}
if (files.Any(f => f.Length == 0))
{
return BadRequest();
}
foreach (var file in files)
{
string folderName = $"Project_{file.FileName}";
string webRootPath = env.WebRootPath;
string newPath = Path.Combine(Startup.documentPath, folderName);
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
if (file.Length > 0)
{
string fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).Name.Trim('"');
string fullPath = Path.Combine(newPath, fileName);
if (System.IO.File.Exists(fullPath))
{
System.IO.File.Delete(fullPath);
}
using (var stream = new FileStream(fullPath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
}
}
return Ok("All the files are successfully uploaded.".csConverToJSON());
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
}

angularjs data not posting from javascript to C# and also service reference not connecting

I have two problems. 1 is that the c# function does not get the js values. Even though when I step through the javascript, the values are in fact there.
The other problem is that my c# post returns a 404 not found error and I see that the debugger never even goes to my other service on localhost123.
Any advice?
This is my angularjs code below
var AddToGroupIds = [];
var RemoveFromGroupIds = [];
angular.forEach($scope.vm.mailingLists, function(f){
if(f.Selected == true){
AddToGroupIds.push(f.Id);
}
else{
RemoveFromGroupIds.push(f.Id);
}
});
return $http({
method: 'POST',
url: '/Contacts/UpdateSubscription',
data: { AddToGroups: AddToGroupIds, RemoveFromGroups: RemoveFromGroupIds, email: 'test#test.com' }
})
.then(function (data) { return data.data; })
this is my c# code below:
[HttpPost]
public void UpdateSubscription(List<int> AddToGroups, List<int> RemoveFromGroups, string email)
{
HttpWebRequest req = null;
var text = "";
try
{
req = HttpWebRequest.CreateHttp(string.Format("http://localhost:123/api/Api/ImmediateUpload?AddToGroupIds={0}&RemoveFromGroupIds={1}&email={2}", AddToGroups, RemoveFromGroups, email));
req.PreAuthenticate = true;
req.Credentials = new NetworkCredential("123", "123", "123");
var res = req.GetResponse();
using (var sr = new StreamReader(res.GetResponseStream()))
{
text = sr.ReadToEnd();
}
res.Close();
}
catch (Exception e)
{
text = e.ToString();
}
}
You cannot post multiple parameters that way. See this article. You can use JObject as the article mentions, or create a UpdateSubscriptionRequest model containing the parameters:
public class UpdateSubscriptionRequest
{
public List<int> AddToGroups { get; set; }
public List<int> RemoveFromGroups { get; set;}
public string Email { get; set;}
}
And change your controller action to:
public void UpdateSubscription([FromBody]UpdateSubscriptionRequest request)

Categories