我有一个与 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/