如何使HttpWebRequest异步 [英] How to make HttpWebRequest async

查看:126
本文介绍了如何使HttpWebRequest异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的代码:

private async Task<string> Request(url)
    {
        Task<string> task = null;

        try
        {
            task = MakeAsyncRequest(url, "text/html");
            return await task;
        }

        catch
        {
            return null;
        }            
    } 

private async Task<string> MakeAsyncRequest(string url, string contentType)
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.ContentType = contentType;
        request.Method = WebRequestMethods.Http.Get;
        request.Timeout = 20000;
        request.Proxy = null;
        Task<WebResponse> task = Task.Factory.FromAsync(
        request.BeginGetResponse,
        asyncResult => request.EndGetResponse(asyncResult),
        (object)null);

            //issue here:
        return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
    }

private string ReadStreamFromResponse(WebResponse response)
    {
        using (Stream responseStream = response.GetResponseStream())
        using (StreamReader sr = new StreamReader(responseStream))
        {
            //Need to return this response 
            string strContent = sr.ReadToEnd();
            return strContent;
        }
    }

我正在呼叫 Request( url) foreach 循环中

foreach(var url in myUrlList)
{
  string body = Request(method).Result;
}

但是由于某些原因,代码在返回时会堆积等待任务。ContinueWith(t => ReadStreamFromResponse(t.Result)); 并冻结。

But for some reason the code getting stacked at return await task.ContinueWith(t => ReadStreamFromResponse(t.Result)); and just freezing.

有没有更好的方法这或也许有人可以解释发生了什么?
我没有遇到任何错误,只是 await ....

Is there a better way of doing this or may be some one can explain what is happening? I am not getting any errors just something wrong with the await....

推荐答案

调用<$正如我在博客中所解释的, foreach 循环中的c $ c>结果导致死锁。总之, await 将捕获一个上下文(例如UI上下文),并使用它来恢复 async 方法。某些上下文(例如,UI上下文)仅在该上下文中允许一个线程。因此,如果通过调用 Result 阻止该特殊线程(例如,UI线程),则 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.

因此,解决方案是更改 foreach 循环:

So, the solution is to change your foreach loop:

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

其他说明:

返回任务的方法应以异步结尾,以遵循 TAP准则

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

Task.Factory.FromAsync 是不必要的; HttpWebRequest 已经具有可等待的方法。更好的选择是使用 HttpClient

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

我建议您不要使用 Task.ContinueWith (或 Task.Result Task.Wait );使用 await 代替。

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

使用以下简化方法:

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);
}

如果更改 HttpWebRequest,则可以进一步简化此代码 HttpClient

这篇关于如何使HttpWebRequest异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆