c# – 如何在没有回调的情况下异步发出Web请求

我有一个服务,在互联网上与第三方交谈,如果我想要扩展,我不希望我的线程被阻止等待响应,当他们可以处理新的请求时.解决此问题的一种方法是使用httpRequest.BeginGetResponse方法并传入回调.这个问题是这个方法立即返回,我没有什么可以回馈给我的服务的调用者.一旦进入回调,我就无法做任何有用的事情.

我想要的是这样的

public string CallServiceNonBlocking(string url) {

   var httpRequest = (HttpWebRequest)WebRequest.Create(url);

   HttpResponse res = httpRequest.FetchNonBlocking(); //this does the work but my thread should  be returned to the asp.net thread pool to do other work rather than blocking here

   return res.GetValue(); 

}

注意我没有.Net 4.5只能用于.NET 4.但是为了参考我可以看到两个版本的解决方案吗?

最佳答案 使用.NET 4.5和C#5.0 async / await进行编码是
very easy.

如果必须,您也可以使它与.NET 4.0 / C#4.0异步工作.您需要从AsyncController派生控制器并使用AsyncManager.基本步骤在“Using an Asynchronous Controller in ASP.NET MVC”中描述.

有鉴于此,您的代码可能看起来像这样(未经测试):

static public Task<WebResponse> GetResponseTapAsync(this WebRequest request)
{
    return Task.Factory.FromAsync(
         (asyncCallback, state) =>
             request.BeginGetResponse(asyncCallback, state),
         (asyncResult) =>
             request.EndGetResponse(asyncResult), null);
}

// ...

public class YourController : AsyncController
{
    public void YourMethodAsyc(string url)
    {
        AsyncManager.OutstandingOperations.Increment();

        var request = (HttpWebRequest)WebRequest.Create(url);
        request.GetResponseTapAsync().ContinueWith(responseTask =>
        {
            try
            {
                var stream = responseTask.Result.GetResponseStream();
                using (var streamReader = new StreamReader(stream))
                {
                    // still blocking here, see notes below
                    var data = streamReader.ReadToEnd();

                    AsyncManager.Parameters["data"] = data;
                }
            }
            finally
            {
                AsyncManager.OutstandingOperations.Decrement();
            }
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }

    public ActionResult YourMethodCompleted(string data)
    {
        return View("Data", new ViewModel
        {
            Data = data
        });
    }
}

您可以进一步实现ReadToEndAsync(因为它在.NET 4.0中不存在),但您将无法使用.请查看this了解更多详情.

理想情况下,如果您需要使用.NET 4.0定位ASP.NET MVC,但在C#5.0中使用VS2012进行开发,您仍然可以使用async / await,Microsoft为此提供了Microsoft.Bcl.Async库.然后你的代码可能如下所示:

public class YourController : AsyncController
{
    async Task<string> YourMethodAsyncImpl(string url)
    {
        var request = (HttpWebRequest)WebRequest.Create(url);
        using (var response = await request.GetResponseAsync()
        using (var streamReader = new StreamReader(response.GetResponseStream())
            return await streamReader.ReadToEndAsync();
    }

    public void YourMethodAsyc(string url)
    {
        AsyncManager.OutstandingOperations.Increment();

        YourMethodAsyncImpl(url).ContinueWith(resultTask =>
        {
            try
            {
                AsyncManager.Parameters["data"] = resultTask.Result;
            }
            finally
            {
                AsyncManager.OutstandingOperations.Decrement();
            }
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }

    public ActionResult YourMethodCompleted(string data)
    {
        return View("Data", new ViewModel
        {
            Data = data
        });
    }
}
点赞