简体   繁体   English

如何使HttpWebRequest异步

[英]How to make HttpWebRequest async

I have such code: 我有这样的代码:

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

I am calling Request(url) in foreach loop 我在foreach循环中调用Request(url)

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

But for some reason the code getting stacked at return await task.ContinueWith(t => ReadStreamFromResponse(t.Result)); 但由于某种原因,代码在return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));堆叠return await task.ContinueWith(t => ReadStreamFromResponse(t.Result)); and just freezing. 只是冷冻。

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 .... 我没有得到任何错误只是await ......

The call to Result in your foreach loop is causing a deadlock , as I explain on my blog. 正如我在博客中解释的那样,在foreach循环中调用Result会导致死锁 In summary, await will capture a "context" (eg, a UI context), and use that to resume the async method. 总之, await将捕获“上下文”(例如,UI上下文),并使用它来恢复async方法。 Some contexts (eg, the UI context) only allow one thread in the context. 某些上下文(例如,UI上下文)仅允许上下文中的一个线程。 So if you block that special thread (eg, the UI thread) by calling Result , then the async method cannot resume execution within that context. 因此,如果通过调用Result阻止该特殊线程(例如,UI线程),则async方法无法在该上下文中继续执行。

So, the solution is to change your foreach loop: 所以,解决方案是改变你的foreach循环:

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

Other notes: 其他说明:

Task-returning methods should end in "Async" to follow the TAP guidelines . 任务返回方法应以“异步”结束,以遵循TAP指南

Task.Factory.FromAsync is unnecessary; Task.Factory.FromAsync是不必要的; HttpWebRequest already has awaitable methods. HttpWebRequest已经有了等待的方法。 An even better option is to use HttpClient instead. 更好的选择是使用HttpClient

I recommend that you not use Task.ContinueWith (or Task.Result , or Task.Wait ); 我建议你不要使用Task.ContinueWith (或Task.Result ,或Task.Wait ); use await instead. await来代替。

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 . 如果将HttpWebRequest更改为HttpClient则可以进一步简化此代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM