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

查看:25
本文介绍了如何使 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;
        }
    }

我在 foreach 循环中调用 Request(url)

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

但由于某种原因,代码在 return await task.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 循环中的 Result 会导致死锁,正如我在我的博客中所解释的那样.总之,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);
}

其他注意事项:

任务返回方法应以Async"结尾,以遵循 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,可以进一步简化此代码.

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

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

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