How to Send/Read Image From HttpResponseMessage [duplicate] - c#

My HttpClient sends the image with PostAsync.
I am not really sure what to do now since this is my first REST Api and I can't really adapt the things I sorted out in other posts yet.
Hopefully you guys can help me out and can give me a direction.
public async Task SendImage(string fullFileName, string fileName)
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://x.x.x.x");
var content = new StringContent(fullFileName, Encoding.UTF8, "image/jpg");
HttpResponseMessage response = await client.PostAsync($"/values/file/{fileName}", content);
}
I have several questions about the POST function.
First of all I can successfully access it with PostMan and the fileName is correct.
How do I read the image data and write it to a file?
[HttpPost("file/{fileName}")]
public void Upload(string fileName)
{
Debug.Write(fileName);
}
EDIT:
I setup my environment and I can now send a post via the internet to my published Web Api.
On my app just nothing happens.
For now I just tried to get something of a message to work on but I dont getting one.
[HttpPost("file/{fileName}")]
public HttpResponseMessage Upload(UploadedFile fileName)
{
Debug.Write(fileName);
if (!ModelState.IsValid)
{
}
if (fileName == null)
{
}
string destinationPath = Path.Combine(#"C:\", fileName.FileFullName);
System.IO.File.WriteAllBytes(destinationPath, fileName.Data);
HttpResponseMessage rm = new HttpResponseMessage();
rm.StatusCode = HttpStatusCode.OK;
return rm;
}

1.Your controller should look like this:
//For .net core 2.1
[HttpPost]
public IActionResult Index(List<IFormFile> files)
{
//Do something with the files here.
return Ok();
}
//For previous versions
[HttpPost]
public IActionResult Index()
{
var files = Request.Form.Files;
//Do something with the files here.
return Ok();
}
2.To upload a file you can also use Multipart content:
public async Task UploadImageAsync(Stream image, string fileName)
{
HttpContent fileStreamContent = new StreamContent(image);
fileStreamContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
var response = await client.PostAsync(url, formData);
return response.IsSuccessStatusCode;
}
}
3.If you are uploading large files you should consider streaming the files instead, you can read about it here

You're going fine until you're trying to retrieve the image data, I'm afraid.
According to your question:
How do I read the image data and write it to a file?
All you want to do is getting the file's data and its file name and sending it to your service.
I would personally create an UploadedFile class on both sides (client and service side), having the file's name and its data, so:
public class UploadedFile
{
public string FileFullName { get; set; }
public byte[] Data { get; set; }
public UploadedFile(string filePath)
{
FileFullName = Path.GetFileName(Normalize(filePath));
Data = File.ReadAllBytes(filePath);
}
private string Normalize(string input)
{
return new string(input
.Normalize(System.Text.NormalizationForm.FormD)
.Replace(" ", string.Empty)
.ToCharArray()
.Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
.ToArray());
}
}
Then you will need, for example, the NewtonSoft's JsonConvert in order to serialize the object and send it through.
So now you would be able to send your data async:
public async Task SendDataAsync(string fullFilePath)
{
if (!File.Exists(fullFilePath))
throw new FileNotFoundException();
var data = JsonConvert.SerializeObject(new UploadedFile(fullFilePath));
using (var client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
await client.UploadStringTaskAsync(new Uri("http://localhost:64204/api/upload/"), "POST", data);
}
}
Now, make sure you correctly handle the request on the server side. If for whatever reason the parameters doesn't match it won't enter into the method (remember having the same model/class - UploadedFile on the service as well).
On the service, just change the arguments of your method and perform something "like this":
[HttpPost]
public HttpResponseMessage Upload(UploadedFile file)
{
if (!ModelState.IsValid)
...
if (file == null)
...
string destinationPath = Path.Combine(_whateverPath, file.FileFullName);
File.WriteAllBytes(destinationPath, file.Data);
}
Hope it helped you having an idea about what to do and what you're actually doing wrong. I've exposed something similar based in my experience.
EDIT: I've actually uploaded an example with both sides working: a simple .NET Core console app which retrieves a file and sends it through POST and a basic WebAPI2 service with a simple controller to retrieve the data. Both ready to go and tested working! Download it here.
Enjoy.

Related

In ASP.NET 4.8, how can I deserilize a file containing JSON, uploaded as POST multipart/form-data request to an object in memory (no file on server)?

Example code:
I export an object as JSON in a file
[HttpGet]
public IHttpActionResult ExportObjectToFile()
{
var exampleObject = new ExampleObject();
var response = Request.CreateResponse(HttpStatusCode.OK, exampleObject, JsonMediaTypeFormatter.DefaultMediaType);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(DispositionTypeNames.Attachment)
{
FileName = exampleObject.FileName;
};
return ResponseMessage(response);
}
Now I want to import and create a new object using multipart/form-data on Postman to attach the file with the request
[HttpPost]
public async Task<IHttpActionResult> ImportObjectFromFile()
{
var multipartForm = await Request.Content.ReadAsMultipartAsync().ConfigureAwait(false);
var jsonString = await multipartForm.Contents[0].ReadAsString().ConfigureAwait(false);
var importedExampleObject = JsonConvert.DeserializeObject<exampleObject>(jsonString);
return ResponseMessage(importedExampleObject);
}
I know it's considered bad practice to not store the file first locally but this is more of a learning exercise for me, it helps me understand how file uploads work.
So with the above code importedExampleObject is created but all the fields are null, essentially all the data is lost, and there are no exceptions thrown, so I'm at a loss.

Define header for upload file in API

I am trying to upload excel file to convert it to Json, but i need to passing through API Gateway. I have problem to passing the file from API Gateway.
I try to set header in ContentDisposition, ContentLength and ContentType manually.
using (var client = new HttpClient())
{
using (var Content = new MultipartFormDataContent())
{
var name = Path.GetFileName(postedFile.FileName);
HttpContent content = new StringContent("");
content.Headers.Clear();
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = name,
FileName = name
};
content.Headers.Add("Content-Length", postedFile.ContentLength.ToString());
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data");
Content.Add(content);
}
HttpResponseMessage reply = new HttpResponseMessage();
reply = await client.GetAsync(#"http://localhost:60897/api/ExceltoJSONConversion");
if (reply.IsSuccessStatusCode)
{
var responseString = await reply.Content.ReadAsStringAsync();
return Json(JsonConvert.DeserializeObject(responseString));
}
}
I have been tried several code but reply always return code 405 MethodNotAllowed.
here my controller where i proceed file
[HttpPost]
[Route("api/ExceltoJSONConversion")]
public IHttpActionResult ExceltoJSONConversion()
{
// Process the file from API Gateway
}
Am i missing something when define Header multipart/form-data? or my code just a mess?
Your API method accepts POST requests only ([HttpPost] attribute).
And in your client you are trying to get API through GET method (client.GetAsync ... ).
Either decorate your API method with [HttpGet] instead of [HttpPost], either change client part to use POST (client.PostAsync ... ).

How to pass form-data and json in same API in Xamarin?

I have an API method in Xamarin that uses .NET Core as a back end and I want to use it to transfer both form-data and JSON format.I have read some examples and I tried to figure a method to make it work.Currently I have this:
public async Task AddUser(User user, MediaFile file)
{
string userRegisterUrl = "http://10.0.2.2:53547/api/PostUser";
var json = JsonConvert.SerializeObject(user);
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
var formData = new MultipartFormDataContent();
formData.Add(new StreamContent(file.GetStream()),"file",string.Format("{0}.png",Guid.NewGuid()));
formData.Add(new StringContent(json),"user");
using (HttpClient client = new HttpClient(clientHandler))
{
var response = await client.PostAsync(userRegisterUrl, formData);
string result = await response.Content.ReadAsStringAsync();
if(response.IsSuccessStatusCode)
{
}
}
}
The problem is that no matter what I do I keep getting this error:"415 Unsupported Media Type".Now I know that what it's trying to say by this is that the server will not accept the payload format as it's unsupported but I have no idea how to do it in such way that it will not require me to install external nuget packages to achieve it.I know it is possible and what I have tried is the following:
First I have tried to create an HttpContent that will get the media file as stream and I added some headers to it with ContentDispositionHeaderValue of "form-data" and a MediaTypeHeaderValue of "application/octet-stream".The json format I would serialize it as I did in my method and pass it to the MultipartFormDataContent value but without any success as I got the error mentioned above.
The second try I didn't pass any headers to the media file,the json object remained unchanged and I used a try catch block to pass the content but without any luck as it gave me the same error.
The method above is the final method that I have implemented and this is what I have on the server-side:
[HttpPost]
public async Task<ActionResult<User>> PostUser(User user,IFormFile file)
{
if (string.IsNullOrWhiteSpace(_env.WebRootPath))
{
_env.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
if(user!=null)
{
_context.User.Add(user);
var users = Path.Combine(_env.WebRootPath, "uploads", user.Name);
if (!Directory.Exists(users)) Directory.CreateDirectory(users);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(users, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
await _context.SaveChangesAsync();
return CreatedAtAction("GetUser", new { id = user.IdUser }, user);
}
Initially I had both methods separated,one for uploading the image and the other for storing user data but I want to create a folder with the user's name every time a new user is registered and someone suggested I should merge the two of them.How can I achieve the desired result without having to deal with the unsupported format?
Alternatif solution you can use Refit to simplify your request. It can be used in any xamarin forms project with/withour ReactiveUI

How can I create headers for a text file and upload it with httpClient?

My text file is saved on my hard disk and I want to upload it in Visual Studio to this file management service: https://learn.microsoft.com/en-us/gaming/playfab/features/data/content-delivery-network/quickstart#fetching-assets
Before uploading, I want to create the file headers, because I want to add a version number of the file to the headers. For example, I want to add "1" to the headers, if it is the first version. How can I do that?
After that, I want to upload the text file. But I don't know how to upload the file with httpClient. How can I upload the file?
I have tried it with this code, but it's not working and I don't know what I'm doing wrong. What is wrong?
private async Task UpoadNewContent()
{
var result = await PlayFabAdminAPI.GetContentUploadUrlAsync(new GetContentUploadUrlRequest()
{
Key = "Levelfiles/Level2.txt",
ContentType = "binary/octet-stream"
});
if (result.Error != null)
{
Console.WriteLine("Error.");
}
else
{
Uri webService = new Uri(result.Result.URL + "Levelfiles/" + "Level2.txt");
await UploadFileAsync(webService, "/Users/myname/TESTFOLDER/Level2.txt");
}
}
async Task UploadFileAsync(Uri uri, string filename)
{
using (var stream = File.OpenRead(filename))
{
var client = new HttpClient();
var response = await client.PostAsync(uri, new StreamContent(stream));
response.EnsureSuccessStatusCode();
}
}
I get this response:

Send image with HttpClient to POST WebApi and consume the data

My HttpClient sends the image with PostAsync.
I am not really sure what to do now since this is my first REST Api and I can't really adapt the things I sorted out in other posts yet.
Hopefully you guys can help me out and can give me a direction.
public async Task SendImage(string fullFileName, string fileName)
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://x.x.x.x");
var content = new StringContent(fullFileName, Encoding.UTF8, "image/jpg");
HttpResponseMessage response = await client.PostAsync($"/values/file/{fileName}", content);
}
I have several questions about the POST function.
First of all I can successfully access it with PostMan and the fileName is correct.
How do I read the image data and write it to a file?
[HttpPost("file/{fileName}")]
public void Upload(string fileName)
{
Debug.Write(fileName);
}
EDIT:
I setup my environment and I can now send a post via the internet to my published Web Api.
On my app just nothing happens.
For now I just tried to get something of a message to work on but I dont getting one.
[HttpPost("file/{fileName}")]
public HttpResponseMessage Upload(UploadedFile fileName)
{
Debug.Write(fileName);
if (!ModelState.IsValid)
{
}
if (fileName == null)
{
}
string destinationPath = Path.Combine(#"C:\", fileName.FileFullName);
System.IO.File.WriteAllBytes(destinationPath, fileName.Data);
HttpResponseMessage rm = new HttpResponseMessage();
rm.StatusCode = HttpStatusCode.OK;
return rm;
}
1.Your controller should look like this:
//For .net core 2.1
[HttpPost]
public IActionResult Index(List<IFormFile> files)
{
//Do something with the files here.
return Ok();
}
//For previous versions
[HttpPost]
public IActionResult Index()
{
var files = Request.Form.Files;
//Do something with the files here.
return Ok();
}
2.To upload a file you can also use Multipart content:
public async Task UploadImageAsync(Stream image, string fileName)
{
HttpContent fileStreamContent = new StreamContent(image);
fileStreamContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
var response = await client.PostAsync(url, formData);
return response.IsSuccessStatusCode;
}
}
3.If you are uploading large files you should consider streaming the files instead, you can read about it here
You're going fine until you're trying to retrieve the image data, I'm afraid.
According to your question:
How do I read the image data and write it to a file?
All you want to do is getting the file's data and its file name and sending it to your service.
I would personally create an UploadedFile class on both sides (client and service side), having the file's name and its data, so:
public class UploadedFile
{
public string FileFullName { get; set; }
public byte[] Data { get; set; }
public UploadedFile(string filePath)
{
FileFullName = Path.GetFileName(Normalize(filePath));
Data = File.ReadAllBytes(filePath);
}
private string Normalize(string input)
{
return new string(input
.Normalize(System.Text.NormalizationForm.FormD)
.Replace(" ", string.Empty)
.ToCharArray()
.Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
.ToArray());
}
}
Then you will need, for example, the NewtonSoft's JsonConvert in order to serialize the object and send it through.
So now you would be able to send your data async:
public async Task SendDataAsync(string fullFilePath)
{
if (!File.Exists(fullFilePath))
throw new FileNotFoundException();
var data = JsonConvert.SerializeObject(new UploadedFile(fullFilePath));
using (var client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
await client.UploadStringTaskAsync(new Uri("http://localhost:64204/api/upload/"), "POST", data);
}
}
Now, make sure you correctly handle the request on the server side. If for whatever reason the parameters doesn't match it won't enter into the method (remember having the same model/class - UploadedFile on the service as well).
On the service, just change the arguments of your method and perform something "like this":
[HttpPost]
public HttpResponseMessage Upload(UploadedFile file)
{
if (!ModelState.IsValid)
...
if (file == null)
...
string destinationPath = Path.Combine(_whateverPath, file.FileFullName);
File.WriteAllBytes(destinationPath, file.Data);
}
Hope it helped you having an idea about what to do and what you're actually doing wrong. I've exposed something similar based in my experience.
EDIT: I've actually uploaded an example with both sides working: a simple .NET Core console app which retrieves a file and sends it through POST and a basic WebAPI2 service with a simple controller to retrieve the data. Both ready to go and tested working! Download it here.
Enjoy.

Categories

Resources