Question

I have a Web API project whose controller in turn makes web requests to a third party REST interface. My controller CRUD functions i have marked as async however the implementation is such that i use HttpWebRequest blocking functions GetRequestStream and GetResponse.

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, or would it allow more concurrent outgoing web requests?

Looking for the best solution for throughput both incoming and outgoing.

Était-ce utile?

La solution

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.

Autres conseils

I would recommend you to retain the async methods, and use HttpClient instead of HttpWebRequest, because it supports asynchronous calls as well.

Let's have a look at a pseudo example of a CarsController calling a third party service.

 public class CarsController : ApiController
    {
        [Route("cars/{id}")]
        public async Task<IHttpActionResult> Get(int id)
        {

            //Get a car by its id

            HttpClient client = new HttpClient();

            //Read the content directly
            string result = await client.GetStringAsync("http://www.google.com");

            //process the result returns from the thrid party REST service

            return Ok(result);
        }

}

As you can see, HttpClient supports reading String/ Stream/ ByteArray asynchronously via GetXXXAsync() methods.

If you want to access to the underlying response content, that can be achieved by using the following code:

        [Route("responsecars/{id}")]
        public async Task<IHttpActionResult> GetResponseStream(int id)
        {
            HttpClient client = new HttpClient();
            HttpResponseMessage responseMessage =await client.GetAsync("http://www.google.com", HttpCompletionOption.ResponseContentRead);

            HttpContent content = responseMessage.Content;

            //using one of the ReadAsync methods
            string text =await content.ReadAsStringAsync();

            return Ok(text);

        }

Hope this help.

Asynchrony on the server is separate and independent from asynchrony on the client.

You can call a synchronous Web API method asynchronously from the client with WebRequest.GetResponseAsync, or you can call an asynchronous Web API method synchronously from the client with WebRequest.GetResponse, or you can have asynchrony on both sides, which is probably the best approach. You don't need to use Begin/End APM-style WebRequest APIs, unless you target .NET 4.0 on the client. Use Task-based async APIs instead.

In either case, a complete HTTP request will be sent to the client when your Web API controller method has fully finished, regardless of whether it is implemented as synchronous or asynchronous (Task-based).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top