Download file using HttpClient while also sending POST data - c#

I am trying to send a json POST request and save the file returned. This is my code:
var obj = new {data = "zip", name = "h.zip"};
string objString = JsonConvert.SerializeObject(obj);
StringContent stringContent = new StringContent(objString, Encoding.UTF8, "application/json");
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Post, downloadUrl))
{
var result = await httpClient.PostAsync(downloadUrl, stringContent);
Console.WriteLine(result.StatusCode);
var contentStream = await result.Content.ReadAsStreamAsync();
Console.WriteLine(contentStream); // debugger confirms that there is a file present
using (FileStream stream = new FileStream(#"C:\Users\mainuser\Desktop\downloadtest\file.zip", FileMode.Create, FileAccess.Write, FileShare.None, Int32.MaxValue)){
Console.WriteLine("copying started");
await contentStream.CopyToAsync(stream);
Console.WriteLine("never gets printed");
}
}
}
It successfully creates a file.zip, but it maintains to be 0KB in size. Also, Console.WriteLine("never gets printed"); never executes. What is the correct way of downloading file using HttpClient?

Related

Getting Some Randam ID when Sending a file using MultipartContent() and HttpClient

I am trying to send a file via an API. I was able to receive the file in my API, but for some reason I am seeing random ID(could be content id) when I read the content in my API.
Previously I was using seeing info about content type and file info as well. I was using MultipartFormDataContent() at that time, then I switched to MultipartContent(). Now the content type and file info is gone, but I still see the id at the start and end of the content.
Code that I am using to send file
using (var formContent = new MultipartContent())
{
byte[] fileByteArray;
using (var binaryReader = new BinaryReader(file.OpenReadStream()))
{
fileByteArray = binaryReader.ReadBytes((int)file.Length);
}
var content = new ByteArrayContent(fileByteArray, 0, fileByteArray.Length);
formContent.Add(content);
// Add the file and it's content
formContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(file.ContentType);
formContent.Headers.ContentType.CharSet = string.Empty;
formContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data");
HttpClient httpClient = new HttpClient();
var task = Task.Run(() => httpClient.PostAsync("MY_END_POINT", formContent));
task.Wait();
HttpResponseMessage response = task.Result;
response.EnsureSuccessStatusCode();
}
Code to read file
using (StreamReader reader = new StreamReader(fileUpload.FileContent))
{
string content = reader.ReadToEnd();
}
Any idea on how the id can be removed?

Sending an image through the body of a PUT request

Title says it all. I need to send an image through the body of a PUT request. This is the code I currently have.
static class Request
{
private readonly static HttpClient client = new HttpClient();
public static async Task<UploadRequest> Upload(string uri, string path)
{
FileStream fileStream = File.Open(path, FileMode.Open, FileAccess.Read);
StreamContent streamContent = new StreamContent(fileStream);
MultipartContent content = new MultipartContent();
content.Add(streamContent);
Debug.WriteLine("Making a PUT request");
var response = await client.PutAsync(uri, content);
var result = await response.Content.ReadAsStringAsync();
var deserializedResult = JsonConvert.DeserializeObject<UploadRequest>(result);
fileStream.Close();
Debug.WriteLine("Request made, returning result");
return deserializedResult;
}
}
Instead of using MultipartContent I instead passed in streamContent directly into client.PutAsync like so.
FileStream fileStream = File.Open(path, FileMode.Open, FileAccess.Read);
StreamContent streamContent = new StreamContent(fileStream);
Debug.WriteLine("Making a PUT request");
var response = await client.PutAsync(uri, streamContent);
However they both produce the same error on my api. Which is "message": "You did not upload an image.". I've checked the actual content of what I've passed in, in both cases when I passed in MultipartContent or streamContent into PutAsync.
The respective output (in order of which I've mentioned them) is System.Net.Http.MultipartContent and System.Net.Http.StreamContent so what exactly am I passing into the body?
Note
I previously asked the wrong question. This is the appropriate one.

Downloading PDF across 2 APIs using GET request

Im trying to download a PDF file crossing over two API's with a GET Request.
If I go direct to API2 the PDF downloads fine with the below code:
Stream fileStream = File.Open(fileLocation, FileMode.Open);
result.Content = new StreamContent(fileStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "test.pdf"
};
return result;
However when I throw API1 into the mix things get a little wonky!!
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
{
var httpRequestMessage = new HttpRequestMessage();
httpRequestMessage.Method = HttpMethod.Get;
httpRequestMessage.RequestUri = new Uri(requestUrl);
HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var content = await response.Content.ReadAsStringAsync();
response.Content = new StringContent(content);
response.EnsureSuccessStatusCode();
response.Content.Headers.ContentEncoding.Add("UTF8");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "test.pdf"
};
return response;
Going direct to API2 produces: %PDF-1.6%âãÏÓ
Going via API2 produces:%PDF-1.6%����
Ive tried changing ContentType and ContentEncoding on API1 with no joy.
Does anything jump out to anyone?
Calling .ReadAsStringAsync on a binary document wont work - you have to call .ReadAsByteArrayAsync.
You also have to use ByteArrayContent instead of StringContent.
not tested

Web Api 2 not returning ByteArrayContent to HTTPClient

I am putting together a test application using WebApi2 and HttpClient in a win forms app.
I have come accross an issue where my HttpClient request to a WebApi2 controller which returns an HttpResponseMessage doesnt return the ByteArrayContent.
WebApiController Code
[HttpGet]
public HttpResponseMessage DownloadFilePart(string fileName)
{
var path = Server.MapPath("~/App_Data/uploads/" + fileName);
var fileArray = System.IO.File.ReadAllBytes(path);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(fileArray)
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue(System.Web.MimeMapping.GetMimeMapping(fileName));
response.Content.Headers.ContentLength = fileArray.Length;
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
return response;
}
WinForms Code using HttpClient
static async void GetFilePart(string hostrUri)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(hostrUri)
};
var request = new HttpRequestMessage(HttpMethod.Get, "/Home/DownloadFilePart/?fileName=Test.txt");
var responseMessage = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var memoryStream = new MemoryStream();
var stream = await responseMessage.Result.Content.ReadAsByteArrayAsync();
var fileToWriteTo = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + "\\Temp\\Test.txt";
using (var fileStream = new FileStream(fileToWriteTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
//copy the content from response to filestream
fileStream.Write(stream, 0, stream.Length);
}
}
When the request return from the WebApi and I write the bytes to file all that is written into the file is the actual headers from the WebApi response. Has anyone any ideas what the issue could be here?
Thanks
Your problem is here
httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
HttpCompletionOption.ResponseHeadersRead is summarized as
The operation should complete as soon as a response is available and headers are read. The content is not read yet.
This would explain why you only get the headers in your response.
Either remove it completely or change it to HttpCompletionOption.ResponseContentRead
static async void GetFilePart(string hostrUri)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(hostrUri)
};
var request = new HttpRequestMessage(HttpMethod.Get, "/Home/DownloadFilePart/?fileName=Test.txt");
var responseMessage = await httpClient.SendAsync(request);
var byteArray = await responseMessage.Content.ReadAsByteArrayAsync();
var fileToWriteTo = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + "\\Temp\\Test.txt";
using (var fileStream = new FileStream(fileToWriteTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
//copy the content from response to filestream
fileStream.Write(byteArray, 0, byteArray.Length);
}
}

Send multipart file using httpclient

I'm trying to post an image to my server using httpclient on Monodroid.
The server-code is ok, infact using Postman all goes well.
This is my code:
var req = new HttpRequestMessage (System.Net.Http.HttpMethod.Post, "http://192.168.0.50:2345/homo");
var content = new MultipartFormDataContent ();
var imageContent = new StreamContent (new FileStream ("my_path.jpg", FileMode.Open, FileAccess.Read, FileShare.Read));
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
content.Add (imageContent, "image", "image.jpg");
req.Content = content;
await client.SendAsync (req);
When I execute this code, on the server side I get this image:
So, like you can see, something comes... but it is not the complete file.
Can you help me?
Thanks a lot!
HttpClient buffers 64k, which probably equals to the data that is shown on the other side. To have it send the file in chunks do something like:
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.TransferEncodingChunked = true;
var content = new MultipartFormDataContent ();
var imageContent = new StreamContent (new FileStream ("my_path.jpg", FileMode.Open, FileAccess.Read, FileShare.Read));
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
content.Add(imageContent, "image", "image.jpg");
await httpClient.PostAsync(url, content);
However, you don't need the multipart if you are only sending one image...

Categories