ASP.NET MVC的异步编程
在上篇《ASP.NET中的异步编程》http://blog.csdn.net/zztfj/article/details/6837985的文章中,我们已经体会到异步编程给网站带来的高性能,高扩展性。现在ASP.NET已经发展到了MVC 3了,那么在MVC中该如何进行异步编程呢?放心,.NET FrameWork已经给我们提供了AsyncController(异步控制器),用它可以实现MVC的异步编程。下面关于它的使用作个简单介绍。
要使用AsyncController进行异步编程需要以下步骤。
1、 不要从 Controller 派生控制器,而应从AsyncController 派生。
2、 为Action创建两个方法。这两个方法分别以Async和Completed结尾。***Async方法返回void,***Completed方法返回ActionResult实例。尽管操作由两个方法组成,但使用与同步操作方法相同的 URL 来访问它(例如Portal/News?city=Seattle)。 其他方法(例如 RedirectToAction 和 RenderAction)还是将按照 News 而不是 NewsAsync 来引用操作方法。传递到 ***sAsync 的参数使用普通的参数绑定机制。传递到 ***Completed 的参数使用 Parameters 字典。
使用AsyncController的注意点:
1、使用OutstandingOperations 属性通知 ASP.NET 有多少个操作已挂起。 这是必要的,因为 ASP.NET 不能确定由操作方法启动了多少个操作或这些操作何时完成。当OutstandingOperations 属性为零时,ASP.NET 可通过调用 ***Completed 方法来完成整个异步操作。
2、如果要将特性应用于异步操作方法,则将它们应用于 ActionAsync 方法,而不是应用于ActionCompleted 方法。 忽略 ActionCompleted 方法上的特性。
已添加两个新的特性:AsyncTimeoutAttribute 和 NoAsyncTimeoutAttribute。 这些特性可让您控制异步超时时间。
3、如果异步操作方法调用一个使用 BeginMethod/EndMethod 模式公开方法的服务,则回调方法(即作为异步回调参数传递到 Begin 方法的方法)可能会在一个不由 ASP.NET 控制的线程上执行。 在此情况下,HttpContext.Current将为 null,并且当应用程序访问 AsyncManager 类的成员(例如 Parameters)时可能会出现争用条件。 若要确保已访问HttpContext.Current 实例并避免争用条件,则可以通过从回调方法中调用 Sync() 来还原 HttpContext.Current。
示例一:在一个方法中调用三个基于事件的异步WebService的示例
private readonly ServiceClient _client = new ServiceClient();
public void AsynchronousAsync() {
ViewData["Title"] = "Parallel asynchronous calls";
AsyncManager.OutstandingOperations.Increment(3);
string city = "Seattle";
_client.GetHeadlinesCompleted += (sender, e) => {
AsyncManager.Parameters["headlines"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
_client.GetHeadlinesAsync(city);
_client.GetScoresCompleted += (sender, e) => {
AsyncManager.Parameters["scores"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
_client.GetScoresAsync(city);
_client.GetForecastCompleted += (sender, e) => {
AsyncManager.Parameters["forecast"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
_client.GetForecastAsync(city);
}
public ActionResult AsynchronousCompleted(NewsHeadline[] headlines, SportsScore[] scores, WeatherForecast[] forecast) {
return View("Common", new ViewModel {
Headlines = headlines,
Scores = scores,
Forecast = forecast
});
}
完整的下载地址:http://archive.msdn.microsoft.com/aspnetmvcsamples/Release/ProjectReleases.aspx?ReleaseId=3547
示例二:调用一个Begin/End模式的异步WebService的示例
public void NewsAsync(string city)
{
AsyncManager.OutstandingOperations.Increment();
_client.BeginGetHeadlines(city, ar =>
{
if (ar.CompletedSynchronously)
{
AsyncManager.Parameters["news"] =
_client.EndGetHeadlines(ar);
AsyncManager.OutstandingOperations.Decrement();
}
else
{
AsyncManager.Sync(() =>
{
AsyncManager.Parameters["news"] =
_client.EndGetHeadlines(ar);
AsyncManager.OutstandingOperations.Decrement();
});
}
}, null);
}
public ActionResult NewsCompleted(NewsHeadline[] headlines)
{
return View("Common", new ViewModel
{
Headlines = headlines
});
}