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.
Related
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?
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);
}
}
I have a Api Post method that I want to be able to accept any file type and that looks like this:
[HttpPost]
public async Task<IHttpActionResult> Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
if (provider.Contents.Count != 1)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest,
"You must include exactly one file per request."));
}
var file = provider.Contents[0];
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = await file.ReadAsByteArrayAsync();
}
This works in fiddler when I try to post an image to it. However, I'm writing a client library and I have a method that looks like this:
public string PostAttachment(byte[] data, Uri endpoint, string contentType)
{
var request = (HttpWebRequest)WebRequest.Create(endpoint);
request.Method = "POST";
request.ContentType = contentType;
request.ContentLength = data.Length;
var stream = request.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
var response = (HttpWebResponse) request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
Whenever I try to post an image using this, I'm getting a UnsuportedMediaType error. I'm assuming it's because my image isn't Multi Part Content? Is there an easy way to make my request of the correct type?
If I have to change my web api post method, is there an easy way of doing that without writing files to the server and keeping it in memory?
The MultipartFormDataContent from the System.Net.Http namespace will allow you to post multipart form data.
private async Task<string> PostAttachment(byte[] data, Uri url, string contentType)
{
HttpContent content = new ByteArrayContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
using (var form = new MultipartFormDataContent())
{
form.Add(content);
using(var client = new HttpClient())
{
var response = await client.PostAsync(url, form);
return await response.Content.ReadAsStringAsync();
}
}
}
I'm calling an existing get method from a WebApi Controller which has this code (I cannot modify it)
[HttpGet]
public HttpResponseMessage Get()
{
XmlDataDocument xmldoc = new XmlDataDocument();
FileStream fs = new FileStream("d:\\document.xml", FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
string str = xmldoc.DocumentElement.InnerXml;
return new HttpResponseMessage() { Content = new StringContent(str, Encoding.UTF8, "application/xml") };
}
I've been trying to read this information like this
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync("http://localhost/api/info");
HttpContent content = rm.Content;
I get a StreamContent but what I like to do now is to read this content and try to deserialize it into a Xml Document in order to read the nodes.
How can I get this information from the Stream Content of the HttpContent?
string response;
using(var http = new HttpClient())
{
response = await http.GetStringAsync("http://localhost/api/info");
}
var xml = new XmlDataDocument();
xml.LoadXml(response);
You can use GetStringAsync to get a string instead of an HttpContent object. You also missed the await in your GetAsync.
Note: code has not been tested
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...