I need to set a timeout of 10 seconds to all the Http web request in Wp8.1 app. I dont find a Timeout instead a ContinueTimeout property in the HttpWebRequest class.
A Quick search gave be few alternatives. Using a CancellationToken being one and the other one is using Task. Will some one give me pointers as to how to modify my current code.
This is how I'm creating a request
string uri = MyClass.HTTP_URI + "user/server-timestamps";
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = MyClass.HTTP_GET;
request.Accept = "application/json";
request.Headers[HTTP_AUTHENTICATION_TOKEN] = "token"
request.Headers[API_KEY] = API_KEY_VALUE;
This is how I'm sending the request
try
{
WebResponse responseObject = await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, request);
HttpWebResponse response = (HttpWebResponse)responseObject;
statusCode = (int)response.StatusCode;
if (statusCode == 200)
{
var responseStream = responseObject.GetResponseStream();
var sr = new StreamReader(responseStream);
received = await sr.ReadToEndAsync();
//Do stuff
}
}
You can use HttpClient class and CancellationTokenSource. Just modify it.
try
{
CancellationTokenSource cts = new CancellationTokenSource(2000);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new Windows.Web.Http.Headers.HttpMediaTypeWithQualityHeaderValue(""));
HttpRequestMessage msg = new HttpRequestMessage(new HttpMethod("POST"), new Uri("Url"));
HttpResponseMessage response = await client.SendRequestAsync(msg).AsTask(cts.Token);
}
catch(TaskCanceledException ex)
{
}
You can create an extension method than accepts CancellationToken and use it like this:
var request = (HttpWebRequest)WebRequest.Create(uri);
// ...
try
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
await request.GetResponseAsyncCancelable(cts.Token);
}
}
catch (OperationCanceledException)
{
// handle cancellation, if desired
}
// ...
public static class HttpWebRequestExt
{
public static async Task<HttpWebResponse> GetResponseAsyncCancelable(
this HttpWebRequest #this,
CancellationToken token)
{
using (token.Register(() => request.Abort(), useSynchronizationContext: false))
{
try
{
// BTW: any reason why not use request.GetResponseAsync,
// rather than FromAsync? It's there in WP 8.1:
// var response = await request.GetResponseAsync();
var response = (HttpWebResponse)await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, request);
token.ThrowIfCancellationRequested();
return response;
}
catch (WebException ex)
{
// WebException caused by cancellation?
if (!token.IsCancellationRequested)
throw; // no, just re-throw
// yes, wrap it with OperationCanceledException
throw new OperationCanceledException(ex.Message, ex, token);
}
}
}
}
BTW, is there any reason you're not using GetResponseAsync, which is there in WP 8.1? See the code comments inline.
Related
I'm using RestSharp to do a GET request Asynchronously but it never ends. If I do the same request Synchronously it ends successfully.
I have used RestSharp just like this before and it always worked.
What am I doing wrong?
Here's the async method: (this.Client is just localhost)
public async Task<ServiceResponse> UpvoteArticleAsync(string source, string url)
{
var client = this.Client;
var request = new RestRequest("service/upvote/"+source+"/"+url, Method.GET) { RequestFormat = DataFormat.Json };
var cancellationTokenSource = new CancellationTokenSource();
var deserial = new JsonDeserializer();
var response = await client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return deserial.Deserialize<ServiceResponse>(response);
}
and this is how I call it:
ServiceResponse result = await rest.UpvoteArticleAsync (this.article.Source, this.article.Url);
As I said if I change the async method to a sync one, it works:
public async Task<ServiceResponse> UpvoteArticleAsync(string source, string url)
{
var client = this.Client;
var request = new RestRequest("service/upvote/"+source+"/"+url, Method.GET) { RequestFormat = DataFormat.Json };
var cancellationTokenSource = new CancellationTokenSource();
var deserial = new JsonDeserializer();
var response = client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return deserial.Deserialize<ServiceResponse>(response.Result);
}
EDIT:
I used try and catch to see if there's any exceptions but it didn't throw any.
EDIT 2:
Even if I do the same request with HttpWebRequest from System.Net it still gets stuck when using the async version of GetResponse:
public async Task<bool> UpvoteArticleAsync(string source, string url)
{
var request = HttpWebRequest.Create(string.Format(#"http://192.168.43.199:8080/service/upvote/{0}/{1}", source, url));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = await request.GetResponseAsync () as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if(string.IsNullOrWhiteSpace(content)) {
Console.Out.WriteLine("Response contained empty body...");
}
else {
Console.Out.WriteLine("Response Body: \r\n {0}", content);
}
}
}
return true;
}
How to set Timeout property to Windows.Web.Http.HttpClient operation. The code sample I used is below.
public HttpClient httpClient;
public CancellationTokenSource cts;
public void SendRequest(addressUri,postrequestbody)
{
HttpHelper.CreateHttpClient(ref httpClient);
cts = new CancellationTokenSource();
HttpRequestMessage msg =
new HttpRequestMessage(new HttpMethod("POST"),
new Uri(addressUri));
msg.Content = new HttpStringContent(postrequestbody);
msg.Content.Headers.ContentType =
new HttpMediaTypeHeaderValue("application/json");
HttpResponseMessage response =
await httpClient.SendRequestAsync(msg).AsTask();
if (response.StatusCode == HttpStatusCode.Ok)
{
}
}
Use a CancellationToken:
try
{
CancellationTokenSource cts = new CancellationTokenSource(2000); // 2 seconds
HttpClient client = new HttpClient();
HttpResponseMessage response = await
client.SendRequestAsync(request).AsTask(cts.Token);
}
catch (TaskCanceledException ex)
{
// Catch operation aborted ...
}
I am trying to catch WebException from asynchronous HttpWebRequest to read soap:fault from api. But it throws AggregateException. Is there a way to catch WebException for Async HttpWebRequest ?
public async Task<XDocument> GetXmlSoapResponseAsync(string soapRequestURL, string xmlData)
{
try
{
//create xml doc
XmlDocument doc = new XmlDocument();
//load xml document frtom xmlData
doc.LoadXml(xmlData);
//creta web request
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(soapRequestURL);
req.ContentType = "text/xml";
req.Accept = "text/xml";
req.Method = "POST";
//GetRequestStream from req
Stream stm = req.GetRequestStream();
doc.Save(stm);
stm.Close();
Task<WebResponse> task = Task.Factory.FromAsync(
req.BeginGetResponse,
asyncResult => req.EndGetResponse(asyncResult),
(object)null);
var response = task.Result;
return await task.ContinueWith(t => ReadStreamFromResponse(response,stm, soapRequestURL,xmlData));
}
catch (WebException webException)
{
LogWebException(webException, soapRequestURL, xmlData);
return null;
}
}
Change this
var response = task.Result;
to this
var response = await task;
await returns the result of the task or unwraps the AggregateException, if any.
Also, .Result blocks the current thread until the result is available, and that's probably not what you want, otherwise you'd just be using the blocking GetResponse, instead of the async BeginGetResponse and EndGetResponse.
Also, you don't even need those two methods. There's a better one - GetResponseAsync
Use this:
var response = await req.GetResponseAsync();
Instead of this:
Task<WebResponse> task = Task.Factory.FromAsync(
req.BeginGetResponse,
asyncResult => req.EndGetResponse(asyncResult),
(object)null);
var response = task.Result;
How I can convert my traditional HttpWebRequest "POST" call with Async / Await pattern, Here with this I am attaching my current code, Any one please help me to convert this code using Async / Await pattern for windows phone 8.
public void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
request.BeginGetRequestStream(GetRequestStreamCallback, new object[] { request, requestBody });
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)((object[])asynchronousResult.AsyncState)[0];
using (var postStream = request.EndGetRequestStream(asynchronousResult))
{
var byteArray = (byte[])((object[])asynchronousResult.AsyncState)[1];
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
}
request.BeginGetResponse(GetResponseCallback, request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)asynchronousResult.AsyncState;
try
{
var response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Since Windows Phone 8 doesn't seem to offer the TAP methods you need such as GetRequestStreamAsync the first thing to do is write a little wrapper to provide them for yourself:
public static class WebRequestAsyncExtensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
{
return Task.Factory.FromAsync<Stream>(
request.BeginGetRequestStream, request.EndGetRequestStream, null);
}
public static Task<WebResponse> GetResponseAsync(this WebRequest request)
{
return Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse, request.EndGetResponse, null);
}
}
Note the use of Task.Factory.FromAsync - this is the preferred way to get an await-friendly wrapper around an APM-based async API such as those offered by WebRequest. This is far more efficient than using Task.Factory.StartNew as suggested by someone else, because that would spin up a new thread, whereas this won't need to.
With this in place, you can now write your code in the same way you would on platforms where these TAP-style methods are available (e.g. Windows 8 store apps, desktop apps, etc.):
public async Task GetEnvironmentVariablesAsync(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
// ASYNC: using awaitable wrapper to get request stream
using (var postStream = await request.GetRequestStreamAsync())
{
// Write to the request stream.
// ASYNC: writing to the POST stream can be slow
await postStream.WriteAsync(requestBody, 0, requestBody.Length);
}
try
{
// ASYNC: using awaitable wrapper to get response
var response = (HttpWebResponse) await request.GetResponseAsync();
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// ASYNC: using StreamReader's async method to read to end, in case
// the stream i slarge.
string responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Note the four lines with // ASYNC: comments - these show where I've made changes. I've collapsed your method down to one, because that's a) possible once you're using async and await and b) much easier than trying to pass things from one method to the next using state arguments.
Notice that the second and fourth of these actually makes async some things you were previously doing synchronously: writing data into the request stream, and reading data out of the response stream. For a small request this probably doesn't matter, but if large amounts of data are being transferred, a synchronous call to Write or ReadToEnd may block. Fortunately, although Windows Phone 8 appears to be missing the TAP methods on WebRequest, it does offer them on Stream and StreamReader so this works without needing to write any extension methods.
I'm new to the community, so here goes my first post. In this case, you can return anytype using a generic Task. This has worked well for me in the past.
Server Side
public class MyController : ApiController
{
public Task<string> PostAsync()
{
return Task.Factory.StartNew(() =>
{
return "populate me with any type and data, but change the type in the response signature.";
});
}
}
Client Side
public class HomeController : Controller
{
public Task<ViewResult> Index()
{
return Task.Factory.StartNew(() =>
{
var model = "use a provider, get some data, or something";
return View(model);
});
}
}
This should do the job:
public async void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback) {
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject {
new JProperty("apiKey", _api),
new JProperty("affiliateId", _affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
var requestBody = Encoding.UTF8.GetBytes(serializedResult);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBody, 0, requestBody.Length);
await GetResponse(request);
}
private async Task GetResponse(WebRequest request) {
Stream resStream = null;
try {
var response = await request.GetResponseAsync();
if (response == null) {
return;
}
resStream = response.GetResponseStream();
if (resStream == null) {
return;
}
var reader = new StreamReader(resStream);
var responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err)) {
CredentialsCallback(Credentails);
}
else {
if (Credentails != null) {
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we) {
if (resStream != null) {
var reader = new StreamReader(resStream);
var responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
}
ErrorCallback(we);
}
}
How can I use HttpWebRequest (.NET, C#) asynchronously?
Use HttpWebRequest.BeginGetResponse()
HttpWebRequest webRequest;
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}
void FinishWebRequest(IAsyncResult result)
{
webRequest.EndGetResponse(result);
}
The callback function is called when the asynchronous operation is complete. You need to at least call EndGetResponse() from this function.
By far the easiest way is by using TaskFactory.FromAsync from the TPL. It's literally a couple of lines of code when used in conjunction with the new async/await keywords:
var request = WebRequest.Create("http://www.stackoverflow.com");
var response = (HttpWebResponse) await Task.Factory
.FromAsync<WebResponse>(request.BeginGetResponse,
request.EndGetResponse,
null);
Debug.Assert(response.StatusCode == HttpStatusCode.OK);
If you can't use the C#5 compiler then the above can be accomplished using the Task.ContinueWith method:
Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse,
request.EndGetResponse,
null)
.ContinueWith(task =>
{
var response = (HttpWebResponse) task.Result;
Debug.Assert(response.StatusCode == HttpStatusCode.OK);
});
Considering the answer:
HttpWebRequest webRequest;
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}
void FinishWebRequest(IAsyncResult result)
{
webRequest.EndGetResponse(result);
}
You could send the request pointer or any other object like this:
void StartWebRequest()
{
HttpWebRequest webRequest = ...;
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest);
}
void FinishWebRequest(IAsyncResult result)
{
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}
Greetings
Everyone so far has been wrong, because BeginGetResponse() does some work on the current thread. From the documentation:
The BeginGetResponse method requires some synchronous setup tasks to
complete (DNS resolution, proxy detection, and TCP socket connection,
for example) before this method becomes asynchronous. As a result,
this method should never be called on a user interface (UI) thread
because it might take considerable time (up to several minutes
depending on network settings) to complete the initial synchronous
setup tasks before an exception for an error is thrown or the method
succeeds.
So to do this right:
void DoWithResponse(HttpWebRequest request, Action<HttpWebResponse> responseAction)
{
Action wrapperAction = () =>
{
request.BeginGetResponse(new AsyncCallback((iar) =>
{
var response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar);
responseAction(response);
}), request);
};
wrapperAction.BeginInvoke(new AsyncCallback((iar) =>
{
var action = (Action)iar.AsyncState;
action.EndInvoke(iar);
}), wrapperAction);
}
You can then do what you need to with the response. For example:
HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.Write(body);
});
public static async Task<byte[]> GetBytesAsync(string url) {
var request = (HttpWebRequest)WebRequest.Create(url);
using (var response = await request.GetResponseAsync())
using (var content = new MemoryStream())
using (var responseStream = response.GetResponseStream()) {
await responseStream.CopyToAsync(content);
return content.ToArray();
}
}
public static async Task<string> GetStringAsync(string url) {
var bytes = await GetBytesAsync(url);
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
I ended up using BackgroundWorker, it is definitely asynchronous unlike some of the above solutions, it handles returning to the GUI thread for you, and it is very easy to understand.
It is also very easy to handle exceptions, as they end up in the RunWorkerCompleted method, but make sure you read this: Unhandled exceptions in BackgroundWorker
I used WebClient but obviously you could use HttpWebRequest.GetResponse if you wanted.
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) => {
args.Result = new WebClient().DownloadString(settings.test_url);
};
worker.RunWorkerCompleted += (sender, e) => {
if (e.Error != null) {
connectivityLabel.Text = "Error: " + e.Error.Message;
} else {
connectivityLabel.Text = "Connectivity OK";
Log.d("result:" + e.Result);
}
};
connectivityLabel.Text = "Testing Connectivity";
worker.RunWorkerAsync();
.NET has changed since many of these answers were posted, and I'd like to provide a more up-to-date answer. Use an async method to start a Task that will run on a background thread:
private async Task<String> MakeRequestAsync(String url)
{
String responseText = await Task.Run(() =>
{
try
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
return new StreamReader(responseStream).ReadToEnd();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
return null;
});
return responseText;
}
To use the async method:
String response = await MakeRequestAsync("http://example.com/");
Update:
This solution does not work for UWP apps which use WebRequest.GetResponseAsync() instead of WebRequest.GetResponse(), and it does not call the Dispose() methods where appropriate. #dragansr has a good alternative solution that addresses these issues.
public void GetResponseAsync (HttpWebRequest request, Action<HttpWebResponse> gotResponse)
{
if (request != null) {
request.BeginGetRequestStream ((r) => {
try { // there's a try/catch here because execution path is different from invokation one, exception here may cause a crash
HttpWebResponse response = request.EndGetResponse (r);
if (gotResponse != null)
gotResponse (response);
} catch (Exception x) {
Console.WriteLine ("Unable to get response for '" + request.RequestUri + "' Err: " + x);
}
}, null);
}
}
Follow up to the #Isak 's answer, which is very good. Nonetheless it's biggest flaw is that it will only call the responseAction if the response has status 200-299. The best way to fix this is:
private void DoWithResponseAsync(HttpWebRequest request, Action<HttpWebResponse> responseAction)
{
Action wrapperAction = () =>
{
request.BeginGetResponse(new AsyncCallback((iar) =>
{
HttpWebResponse response;
try
{
response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar);
}
catch (WebException ex)
{
// It needs to be done like this in order to read responses with error status:
response = ex.Response as HttpWebResponse;
}
responseAction(response);
}), request);
};
wrapperAction.BeginInvoke(new AsyncCallback((iar) =>
{
var action = (Action)iar.AsyncState;
action.EndInvoke(iar);
}), wrapperAction);
}
And then as #Isak follows:
HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.Write(body);
});
I've been using this for async UWR, hopefully it helps someone
string uri = "http://some.place.online";
using (UnityWebRequest uwr = UnityWebRequest.Get(uri))
{
var asyncOp = uwr.SendWebRequest();
while (asyncOp.isDone == false) await Task.Delay(1000 / 30); // 30 hertz
if(uwr.result == UnityWebRequest.Result.Success) return uwr.downloadHandler.text;
Debug.LogError(uwr.error);
}