Client-Side error when uploading image on server ASP.NET Core - image

I am struggling with uploading an image from thew client-side to a folder on the server-side in .Net Core.I used Postman to check if the method on the server-side is working and it does without any problem,but when I try to upload an image from the client-side,I get an error on the server-side of type NullReferenceException:Object reference not set to an instance of an object.This is the Post method on the server-side:
[HttpPost]
public async Task Post(IFormFile file)
{
if (string.IsNullOrWhiteSpace(_environment.WebRootPath))
{
_environment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
//var fileName = file.FileName.Split('\\').LastOrDefault().Split('/').LastOrDefault();
if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
Apparently the method is thrown where I check if the length of the file is bigger than 0.On the client-side I get error "500 internal server error" and I tried to check using the debugger where exactly the error is thrown but i can't find anything that could resemble an error of some sort.This is the API method for the client-side:
public async Task UploadPictureAsync(MediaFile image)
{
User user = new User();
string pictureUrl = "http://10.0.2.2:5000/api/UploadPicture";
HttpContent fileStreamContent = new StreamContent(image.GetStream());
// user.Picture=GetImageStreamAsBytes(image.GetStream());
fileStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {FileName=Guid.NewGuid() + ".Png",Name="image"};
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
using (var client = new HttpClient(clientHandler))
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
var response = await client.PostAsync(pictureUrl, formData);
if(response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
}
}
The image is declared in the Model as byte array:
public byte[] Picture { get; set; }
Does someone understand why my POST method has this behavior since the server-side works perfectly but fails when I try to upload an image from the client-side?What I find weird though is that when i read the error and I look at the Content-Type it is "text/plain" instead of "form-data" and I have tried to set it at the MutipartFormDataContent like this:
formData.Headers.ContentType.MediaType = "multipart/form-data";
I also tried to set the MediaTypeHeaderValue on the client like this:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
I still get the wrong content type.
I have also tried a different approach with Stream instead of MediaFile but without any luck as it did not even hit the break point in debugger mode for the response.Any help would be appreciated! :)

I have managed to find the answer finalllyyyyy!!!The problem was on the client-side as I suspected and guess what,it was all about the correct name.It turns out that since on the server side I have IFormFile file I had to change the client side to take the parameter name "file" instead of image as well so that it could work.Thank you #Jason for the suggestions as I didn't understand the error from the first place and did some debugging on the server-side to help me figure it out.

Related

How to resolve StatusCode: 415, ReasonPhrase: 'Unsupported Media Type'?

How do you post a file with HttpClient?
It can't be that hard, can it?
I am posting a file from a Windows forms client to an ASP.Net Core 2.2 website API (not WebApi)
The file could be anything, word, pdf, image, video etc...
The file could be anything up to 500MB and my JSON methods won't send anything above 25MB
No matter what I do I keep getting
StatusCode: 415, ReasonPhrase: 'Unsupported Media Type'
I can't work out what's gong wrong I have no idea what's missing. I've narrowed it down to this
string filepath = file;
string filename = Path.GetFileName(file);
MultipartFormDataContent content = new MultipartFormDataContent();
var fileContent = new StreamContent(File.OpenRead(filepath));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { FileName = $"\"{filename}\"" };
content.Add(fileContent);
HttpResponseMessage response = await _httpClient.PostAsync(serviceMethod, content);
All the examples I've read (loads of them), most seem to be sensing JSON and I can do that in spades. The rest tell you what to read and look for but I'm still lost I just want to post a file. I have the server code ready to go.
[HttpPost]
public async Task<JsonResult> UploadFile([FromForm]IFormFile result)
I'll keep reading but any help would be much appreciated.
Ok, I got a bit closer. I've updated my code (see above) and now the controller on my API is getting invoked but now result is null
Try to change your code as shown:
public async Task<IActionResult> PostFile()
{
string filepath =file;
string filename = Path.GetFileName(file);
MultipartFormDataContent content = new MultipartFormDataContent();
var fileContent = new StreamContent(System.IO.File.OpenRead(filepath));
content.Add(fileContent, "result", filename);
HttpResponseMessage response = await _httpClient.PostAsync(serviceMethod, content);
}
[HttpPost]
public async Task<JsonResult> UploadFile(IFormFile result)
Result

Cant upload files using loopback Storage component REST API in Xamarin

I am using loopback Storage component REST API in Xamarin to finish a file uploading job. However, it does not work and does not return any exceptions to me.
Here is my code:
library using: RestSharp.portable
public async Task addFiles(string name, byte[] file)
{
try
{
var client = new RestClient(App.StrongLoopAPI);
var request = new RestRequest("containers/container1/upload", HttpMethod.Post);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "multipart/form-data");
request.AddFile("file", file, name + ".jpg", System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"));
var res = await client.Execute(request);
}
catch (Exception ex)
{
//return null;
}
}
Does my function have any problems?
You're setting the Content Type (Mime Type) wrong.
AddFile accepts as the last parameter the Content Type (for example image/jpeg for a JPG image), where you're using multipart/form-data.
There are different ways to figure out the Content Type of a file, see here:
Get MIME type from filename extension
This should fix your issue.

Read both key values and files from multipart from data post request in ASP.NET WebAPI

I have an endpoint that needs to accept a file upload and also some other information from the client request. With the following code I can upload the file successfully but can't seem to figure out how to read the other info.
I make a test request from Postman with the following form data:
image -- myimage.jpg -- of type File
email -- a#b.com -- of type Text
The backend code looks like this:
[HttpPost]
public async Task<HttpResponseMessage> SharePhoto()
{
try
{
var provider = new MultipartMemoryStreamProvider();
var data = await Request.Content.ReadAsMultipartAsync(provider);
// this is how I get the image which I am succesfully passing to EmailService
var item = (StreamContent)provider.Contents[0];
using (var stream = new MemoryStream())
{
await item.CopyToAsync(stream);
String emailAddress;
EmailService.SendSharedPhoto(emailAddress, stream);
return Request.CreateResponse();
}
}
catch
{
// do stuff
}
}
In this example I am able to access provider.Contents[1] but can't seem to be able to get the value from it into emailAddress. I'm thinking it may be possible to use the same trick as the await item.CopyToASync(stream) from the image upload, but I'm hoping I can get a simpler solution to that. Any ideas?
I just barely answered a very similar question to this yesterday. See my answer here complete with sample controller code.
The method I ended up using is:
If the form elements are strings (and it worked for me since the mobiel frontend took responsability for input data) you can do this:
var streamContent = (StreamContent)provider.Contents[1];
var memStream = new MemoryStream();
await streamContent.CopyToAsync(memStream);
var actualString = Encoding.UTF8.GetString(x.ToArray());
If however the field needs to represent a collection of items, like for example the email list: ["a#b.com", "x#c.com"], etc a JavaScriptSerializer can be user, like so:
var streamContent = (StreamContent)provider.Contents[1];
var emailAddresses = await str.ReadAsStringAsync();
var jsSerializer = new JavaScriptSerializer();
var deserializedData = jsSerializer.Deserialize<string[]>(emailAddresses);
Note that this is nowhere near safe, though it is few lines of code and happens to work.

How to retrieve message from WEB API?

I created some web apis and when an error happens the api returns HttpResponseMessage that is created with CreateErrorResponse message. Something like this:
return Request.CreateErrorResponse(
HttpStatusCode.NotFound, "Failed to find customer.");
My problem is that I cannot figure out how to retrieve the message (in this case "Failed to find customer.") in consumer application.
Here's a sample of the consumer:
private static void GetCustomer()
{
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string data =
"{\"LastName\": \"Test\", \"FirstName\": \"Test\"";
var content = new StringContent(data, Encoding.UTF8, "application/json");
var httpResponseMessage =
client.PostAsync(
new Uri("http://localhost:55202/api/Customer/Find"),
content).Result;
if (httpResponseMessage.IsSuccessStatusCode)
{
var cust = httpResponseMessage.Content.
ReadAsAsync<IEnumerable<CustomerMobil>>().Result;
}
}
Any help is greatly appreciated.
Make sure you set the accept and or content type appropriately (possible source of 500 errors on parsing the request content):
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
Then you could just do:
var errorMessage = response.Content.ReadAsStringAsync().Result;
That's all on the client of course. WebApi should handle the formatting of the content appropriately based on the accept and/or content type. Curious, you might also be able to throw new HttpResponseException("Failed to find customer.", HttpStatusCode.NotFound);
One way to get the message is to do:
((ObjectContent)httpResponseMessage.Content).Value
This will give you a dictionary that contains also the Message.
UPDATE
Refer to the official page:
http://msdn.microsoft.com/en-us/library/jj127065(v=vs.108).aspx
You have to vary the way you're reading the successful response and the error response as one is obviously in your case StreamContent, and the other should be ObjectContent.
UPDATE 2
Have you tried doing it this way ?
if (httpResponseMessage.IsSuccessStatusCode)
{
var cust = httpResponseMessage.Content.
ReadAsAsync<IEnumerable<CustomerMobil>>().Result;
}
else
{
var content = httpResponseMessage.Content as ObjectContent;
if (content != null)
{
// do something with the content
var error = content.Value;
}
else
{
Console.WriteLine("content was of type ", (httpResponseMessage.Content).GetType());
}
}
FINAL UPDATE (hopefully...)
OK, now I understand it - just try doing this instead:
httpResponseMessage.Content.ReadAsAsync<HttpError>().Result;
This is an option to get the message from the error response that avoids making an ...Async().Result() type of call.
((HttpError)((ObjectContent<HttpError>)response.Content).Value).Message
You should make sure that response.Content is of type ObjectContent<HttpError> first though.
It should be in HttpResponseMessage.ReasonPhrase. If that sounds like a bit of a strange name, it's just because that is the way it is named in the HTTP specification http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
OK this is hilarious, but using QuickWatch I came up with this elegant solution:
(new System.Collections.Generic.Mscorlib_DictionaryDebugView(((System.Web.Http.HttpError)(((System.Net.Http.ObjectContent)(httpResponseMessage.Content)).Value)))).Items[0].Value
That is super readable!

ActionScript 3.0 To Send POST and get data from .Net 4 using MVC

I am trying to get my flash application to send a request back to the webserver so that it can get some information. So far after reading on stackoverflow for a while and on the net I have some code written, but its not quite working right. I need just a little help tying it all together.
Here is the controller for my webserver
//
// POST: /Home/HoneyPot
[HttpPost]
public ActionResult HoneyPot(bool GetData)
{
//ViewBag.
return View();
}
Here is the ActionScript code that is supposed to be making the request.
// get dynamic page element information
var myData:URLRequest = new URLRequest("http://localhost:59418/HoneyPot");
myData.method = URLRequestMethod.POST;
var vars:URLVariables = new URLVariables();
vars.Input = "GetData=true";
myData.data = vars;
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE, gotPostData_Spiral);
loader.load(myData);
function gotPostData_Spiral(anEvent:Event):void
{
var postData = anEvent.target.data.myVar;
}
Right now when I run the flash code I get this output back:
Error opening URL 'http://localhost:59418/HoneyPot'
Error: Error #2101: The String passed to URLVariables.decode() must be a URL-encoded query
string containing name/value pairs.
at Error$/throwError()
at flash.net::URLVariables/decode()
at flash.net::URLVariables()
at flash.net::URLLoader/onComplete()
Thank you for the help
Instead of:
vars.Input = "GetData=true";
try:
vars.GetData = "true";

Resources