I'm trying to download an image from the internet, through the URL, to my Windows8-app and convert it to a byte[]. (BitmapImage isn't serializable)
Unfortunatly when I try to process this code, it crashes on the bytearray initialization since the Stream isn't seekable.
Is there ANY way to accomplish this? I've red that there isn't a stream yet that is seekable in WinRT...
private async Task<byte[]> DownloadImageFromWebsite(string url)
{
//BitmapImage result = null;
byte[] result = null;
try
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
WebResponse response = await request.GetResponseAsync();
Stream imageStream = response.GetResponseStream();
result = new byte[imageStream.Length];
await imageStream.ReadAsync(result, 0, (int)imageStream.Length);
response.Dispose();
}
catch (Exception ex)
{
return null;
}
return result;
}
Your problem is this line:
result = new byte[imageStream.Length];
For an HTTP response stream, you don't know how big it will be until it's read.
If the server sends a Content-Length header, then you should be able to read it and size your array using it. However, you'll still have to fall back to reading the entire stream (of unknown size) into memory, as such:
private async Task<byte[]> DownloadImageFromWebsiteAsync(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
using (WebResponse response = await request.GetResponseAsync())
using (var result = new MemoryStream())
{
await imageStream.CopyToAsync(result);
return result.ToArray();
}
}
catch (WebException ex)
{
return null;
}
}
P.S. I recommend you use HttpClient instead of HttpWebRequest.
Related
I am trying to make a program that requests my website with a username, password, hardware ID and a key in POST.
I have this code here that should send a POST request to my website with that form data, but when it sends, my webserver reports back that it didn't receive the POST data
try
{
string poststring = String.Format("username={0}&password={1}&key={2}&hwid={3}", Username, Password, "272453745345934756392485764589", GetHardwareID());
HttpWebRequest httpRequest =
(HttpWebRequest)WebRequest.Create("mywebsite");
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
byte[] bytedata = Encoding.UTF8.GetBytes(poststring);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
HttpWebResponse httpWebResponse =
(HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = httpWebResponse.GetResponseStream();
StringBuilder sb = new StringBuilder();
using (StreamReader reader =
new StreamReader(responseStream, System.Text.Encoding.UTF8))
{
string line;
while ((line = reader.ReadLine()) != null)
{
sb.Append(line);
}
}
return sb.ToString();
}
catch (Exception Error)
{
return Error.ToString();
}
If someone could help me, I would really appreciate it.
As per HttpWebRequest documentation
We don't recommend that you use HttpWebRequest for new development. Instead, use the System.Net.Http.HttpClient class.
HttpClient contains only asynchronous API because Web requests needs awaiting. That's not good to freeze entire Application while it's pending response.
Thus, here's some async function to make POST request with HttpClient and send there some data.
First of all, create HttpClient seperately because
HttpClient is intended to be instantiated once per application, rather than per-use.
private static readonly HttpClient client = new HttpClient();
Then implement the method.
private async Task<string> PostHTTPRequestAsync(string url, Dictionary<string, string> data)
{
using (HttpContent formContent = new FormUrlEncodedContent(data))
{
using (HttpResponseMessage response = await client.PostAsync(url, formContent).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}
Or C# 8.0
private async Task<string> PostHTTPRequestAsync(string url, Dictionary<string, string> data)
{
using HttpContent formContent = new FormUrlEncodedContent(data);
using HttpResponseMessage response = await client.PostAsync(url, formContent).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
Looks easier than your code, right?
Caller async method will look like
private async Task MyMethodAsync()
{
Dictionary<string, string> postData = new Dictionary<string, string>();
postData.Add("message", "Hello World!");
try
{
string result = await PostHTTPRequestAsync("http://example.org", postData);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
If you're not familiar with async/await, it's time to say Hello.
I've got a web service that returns an http 500 with some diagnostic information in the body of the response.
I'm doing something like
Stream responseStream = null;
WebResponse _Response = null;
Stream responseStream = null;
HttpWebRequest _Request = null;
try
{
_Response = _Request.GetResponse();
responseStream = _Response.GetResponseStream();
}
catch {
//try to view the Request.GetResponse() body here.
}
Since _Request.GetResponse() is returning an http 500 there doesn't seem to be a way to view the response body. According to HTTP 500 Response with Body? this was a known issue in Java 9 years ago. I'm wondering if there's a way to do it in .NET today.
The microsoft docs give a good run down of what HttpWebRequest.GetResponse returns if it fails, you can check it out here https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest.getresponse?view=netframework-4.8
In your example I believe you need to check for WebException and handle it.
Stream responseStream = null;
WebResponse _Response = null;
Stream responseStream = null;
HttpWebRequest _Request = null;
try
{
_Response = _Request.GetResponse();
responseStream = _Response.GetResponseStream();
}
catch (WebException w)
{
//here you can check the reason for the web exception
WebResponse res = w.Response;
using (Stream s = res.GetResponseStream())
{
StreamReader r= new StreamReader(s);
string exceptionMessage = r.ReadToEnd(); //here is your error info
}
}
catch {
//any other exception
}
I've recently written a C# function that does a multi part form post for uploading files. To track the progress, I'd write the form data to the request stream at 4096 bytes at a time and call back with each write. However, it seems that the request does not even get sent until GetResponseAsync() is called.
If this is the case, is the reporting of every 4096 bytes written to the request stream an accurate reporting of upload progress?
If not, how can I accurately report progress? WebClient is out of the question for me, this is in a PCL Xamarin project.
private async Task<string> PostFormAsync (string postUrl, string contentType, byte[] formData)
{
try {
HttpWebRequest request = WebRequest.Create (postUrl) as HttpWebRequest;
request.Method = "POST";
request.ContentType = contentType;
request.Headers ["Cookie"] = Constants.Cookie;
byte[] buffer = new byte[4096];
int count = 0;
int length = 0;
using (Stream requestStream = await request.GetRequestStreamAsync ()) {
using (Stream inputStream = new MemoryStream (formData)) {
while ((count = await inputStream.ReadAsync (buffer, 0, buffer.Length)) > 0) {
await requestStream.WriteAsync (buffer, 0, count);
length += count;
Device.BeginInvokeOnMainThread (() => {
_progressBar.Progress = length / formData.Length;
});
}
}
}
_progressBar.Progress = 0;
WebResponse resp = await request.GetResponseAsync ();
using (Stream stream = resp.GetResponseStream ()) {
StreamReader respReader = new StreamReader (stream);
return respReader.ReadToEnd ();
}
} catch (Exception e) {
Debug.WriteLine (e.ToString ());
return String.Empty;
}
}
Please note that I am asking about monitoring progress of an upload at 4096 bytes at a time, not a download
I ended up accomplishing this by setting the AllowWriteStreamBuffering property of the WebRequest equal to false and the SendChunked property to true.
HOWEVER Xamarin.PCL (Profile 78) does not allow you to access these properties of the HttpWebRequest, so I had to instantiate my HttpWebRequest and return it from a dependency service in my platform specific project (only tested in iOS).
public class WebDependency : IWebDependency
{
public HttpWebRequest GetWebRequest(string uri)
{
var request = WebRequest.Create (uri) as HttpWebRequest;
request.SendChunked = true;
request.AllowWriteStreamBuffering = false;
return request;
}
}
And then to instantiate my web request -
HttpWebRequest request = DependencyService.Get<IWebDependency>().GetWebRequest(uri);
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 have a desktop client, that communicates with serverside via Http.
When server has some issues with data processing it returns description of an error in JSON in Http response body with proper Http-code (mainly it is HTTP-400).
When i read HTTP-200 response everithing's fine and this code works:
using (var response = await httpRequest.GetResponseAsync(token))
{
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
return await reader.ReadToEndAsync();
}
}
But when an error occures and WebException is thrown and caught there is this code:
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var response = (HttpWebResponse) ex.Response)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
{
var json = reader.ReadToEnd();
}
}
}
}
}
I have already done something to it to maybe make it work, but the next happens:
response.ContentLength is valid (184)
but stream.Length is 0
and after that i can't read json (it's "")
I don't even know where to look, because everything looks like it should work.
What might be the problem?
After a month of almost everyday thinking I've found workaround.
The thing was that WebException.Response.GetResponseStream() returns not exactly the same stream that was obtained during request (can't find link to msdn right now) and by the time we get to catch the exception and read this stream the actual response stream is lost (or something like that, don't really know and was unable to find any info on the net, except looking into CLRCore which is now opensource).
To save the actual response until catching WebException you must set KeepAlive Property on your HttpRequest and voila, you get your response while catching exception.
So the working code looks like that:
try
{
var httpRequest = WebRequest.CreateHttp(Protocol + ServerUrl + ":" + ServerPort + ServerAppName + url);
if (HttpWebRequest.DefaultMaximumErrorResponseLength < int.MaxValue)
HttpWebRequest.DefaultMaximumErrorResponseLength = int.MaxValue;
httpRequest.ContentType = "application/json";
httpRequest.Method = method;
var encoding = Encoding.GetEncoding("utf-8");
if (httpRequest.ServicePoint != null)
{
httpRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
httpRequest.ServicePoint.MaxIdleTime = 5000;
}
//----HERE--
httpRequest.KeepAlive = true;
//----------
using (var response = await httpRequest.GetResponseAsync(token))
{
using (var reader = new StreamReader(response.GetResponseStream(), encoding))
{
return await reader.ReadToEndAsync();
}
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var response = (HttpWebResponse)ex.Response)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
{
return reader.ReadToEnd();
//or handle it like you want
}
}
}
}
}
I don't know if it is good to keep all connection alive like that, but since it helped me to read actual responses from server, i think it might help someone, who faced the same problem.
EDIT: Also it is important not to mess with HttpWebRequest.DefaultMaximumErrorResponseLength.
I remember facing similar issue before and there was something related to setting the stream's position. Here is one of my solutions for reading webResponse that worked for me earlier. Please try if similar approach works for you:-
private ResourceResponse readWebResponse(HttpWebRequest webreq)
{
HttpWebRequest.DefaultMaximumErrorResponseLength = 1048576;
HttpWebResponse webresp = null;// = webreq.GetResponse() as HttpWebResponse;
var memStream = new MemoryStream();
Stream webStream;
try
{
webresp = (HttpWebResponse)webreq.GetResponse();
webStream = webresp.GetResponseStream();
byte[] readBuffer = new byte[4096];
int bytesRead;
while ((bytesRead = webStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
memStream.Write(readBuffer, 0, bytesRead);
}
catch (WebException e)
{
var r = e.Response as HttpWebResponse;
webStream = r.GetResponseStream();
memStream = Read(webStream);
var wrongLength = memStream.Length;
}
memStream.Position = 0;
StreamReader sr = new StreamReader(memStream);
string webStreamContent = sr.ReadToEnd();
byte[] responseBuffer = Encoding.UTF8.GetBytes(webStreamContent);
//......
//.......
Hope this helps!