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

标签 c# asp.net asynchronous .net-4.0 async-await

我有一个与 Internet 上的第 3 方对话的服务,如果我想扩展它,我不希望我的线程在可以处理新请求时被阻塞以等待响应。解决此问题的一种方法是使用 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 派生您的 Controller 并使用 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 中不存在),但您将无法使用 using。检查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
        });
    }
}

关于c# - 如何在没有回调的情况下异步发出 Web 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22716310/

相关文章:

c# - 如何在 ConfiguredTaskAwaitable 上显示 ".Wait( )"?

javascript - 如何从异步调用返回响应?

java - 应用程序无法使用 @Async 注释启动

javascript - 在javascript中的DataList中查找Div

c# - C# 探查器如何工作?

c# - 使窗口始终位于另一个已经位于顶部的窗口之上?

c# - 自定义客户端消息

asp.net - 网页的 SQL Reporting Services 查看器 - 您可以移动查看报告按钮吗?

c# - 仅在注销时清除浏览器缓存

c# - 如何在 asp.net 中使用 mvc2 验证隐藏任何页面元素