How to Use Httpwebrequest (.Net) Asynchronously

How to use HttpWebRequest (.NET) 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.

Async HttpWebRequest call using C#

I suppose the best way for making an async request is HttpClient.
You can write something like this:

var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("xxxxxx"),
Method = HttpMethod.Get,
};

request.Headers.Accept.Add(new ....);
var response = await client.SendAsync(request);
//read a result from the repsonse

How to make HttpWebRequest async

The call to Result in your foreach loop is causing a deadlock, as I explain on my blog. In summary, await will capture a "context" (e.g., a UI context), and use that to resume the async method. Some contexts (e.g., the UI context) only allow one thread in the context. So if you block that special thread (e.g., the UI thread) by calling Result, then the async method cannot resume execution within that context.

So, the solution is to change your foreach loop:

foreach(var url in myUrlList)
{
string body = await ProcessAsync(method);
}

Other notes:

Task-returning methods should end in "Async" to follow the TAP guidelines.

Task.Factory.FromAsync is unnecessary; HttpWebRequest already has awaitable methods. An even better option is to use HttpClient instead.

I recommend that you not use Task.ContinueWith (or Task.Result, or Task.Wait); use await instead.

With these simplifications in place:

private async Task<string> MakeAsyncRequestAsync(string url, string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = WebRequestMethods.Http.Get;
request.Timeout = 20000;
request.Proxy = null;
WebResponse response = await request.GetResponseAsync();
return ReadStreamFromResponse(response);
}

This code could be simplified further if you change HttpWebRequest to HttpClient.

How to make a HttpWebRequest function Async?


 HttpClient client = new HttpClient();  

public async Task PostAsync(string actionName, object json)
{
var content = new StringContent(json.ToString(), Encoding.UTF8,"application/json");
var resultRoles = await client.PostAsync(new Uri(actionName),content);
}

You're new so I wont go into detail about HttpClient, but the instance should be reused. Try to do some self research on how this should be accomplished.

Implementing HttpWebRequest Async calls

The documentation has a good example (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream(v=vs.100).aspx):

using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;

class HttpWebRequestBeginGetRequest
{
private static ManualResetEvent allDone = new ManualResetEvent(false);
public static void Main(string[] args)
{
// Create a new HttpWebRequest object.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/example.aspx");

request.ContentType = "application/x-www-form-urlencoded";

// Set the Method property to 'POST' to post data to the URI.
request.Method = "POST";

// start the asynchronous operation
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);

// Keep the main thread from continuing while the asynchronous
// operation completes. A real world application
// could do something useful such as updating its user interface.
allDone.WaitOne();
}

private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);

Console.WriteLine("Please enter the input data to be posted:");
string postData = Console.ReadLine();

// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);

// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();

// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}

private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();

// Release the HttpWebResponse
response.Close();
allDone.Set();
}

HttpWebRequest async versus Begin/End


the controller is marked async but the implementation uses synchronous HttpWebRequest calls, in that my controller is awaiting Task.Run( sync web request )

Think about what is happening in the request. The request comes in and ASP.NET takes a thread pool thread to handle the request. The controller action queues the work to the thread pool (taking up another thread), and then awaits that work, freeing up the original request thread. You haven't gained anything by using await because there's still a thread pool thread blocking on the web request.

For this reason, you should almost never use Task.Run (or any other method that queues work to the thread pool) on ASP.NET.

Is this suitable or should i use the Begin/End methods of HttpWebRequest too. This seems like overkill as it would be asyncing an already async operation

It's not really asynchronous right now; there's still a thread being blocked. I call this "queue blocking work to a thread pool thread and then await it" technique fake asynchrony.

The appropriate fix is to use HttpClient, which was designed for asynchronous use; or, you could use TaskFactory<T>.FromAsync to wrap the Begin/End methods into an awaitable task.

The thing i dont understand though is if i use await HttpClient.SendAsync then somewhere something must be blocking waiting for a response

No, there doesn't have to be something blocking somewhere. As I describe on my blog, in a truly asynchronous scenario (i.e., not fake-asynchrony), there is no thread.

How can I use System.Net.HttpWebRequest with async/await?

If you use a generic Task<>.Factory you get a little more type-safety:

var request = WebRequest.CreateHttp("https://www.google.com");
object state = null; // or whatever state you want.
var task = Task<WebResponse>.Factory.FromAsync(
request.BeginGetResponse,
request.EndGetResponse,
state);

However, as with when you're not doing async calls, if you want an HttpWebResponse rather than just a WebResponse, you'll need to do an additional cast. And be sure to close/dispose your response:

using (var response = (HttpWebResponse) (await task))
{
// use response
}

WebRequest async asp.net-mvc

sorry, I didn't quite understand that I didn't insert my attempts to use async, I did it, and it seems to work, can I improve something in my code? added 2 lines

  public async Task<IEnumerable<JiraDataModel>> GetData(string dateFrom, string dateTo)
{
int allTicketsCount = 0;
int devTicketsCount = 0;
int slaTicketsCount = 0;

List<JiraRequestUrl> urlArray = new List<JiraRequestUrl>();

urlArray.AddRange(new List<JiraRequestUrl>
{
new JiraRequestUrl{type = "all", //*data*//},
new JiraRequestUrl(){type = "dev",//*data*//});

try
{
foreach (JiraRequestUrl u in urlArray)
{
WebRequest request = WebRequest.Create(_jiraUrl + u.url);
request.ContentType = "application/json; charset=utf-8";
request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(_credentials)));
request.Headers.Add("maxResults", "100");

HttpWebResponse response = (HttpWebResponse)(await request.GetResponseAsync()request.GetResponse();

if (response.StatusCode == HttpStatusCode.OK)
{
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
JiraGetDataModel.RootObject DeserializedResponse = (JiraGetDataModel.RootObject)JsonConvert.DeserializeObject(responseString, typeof(JiraGetDataModel.RootObject));

if (u.type.Equals("all"))
{
allTicketsCount = DeserializedResponse.total;
}
if (u.type.Equals("dev"))
{
devTicketsCount = DeserializedResponse.total;
}
}
}


Related Topics



Leave a reply



Submit