從ASP.NET MVC 2到4看異步控制器
這篇文章主要針對即將到來的ASP.NET MVC4中的異步控制器做一個回顧和展望, 并未涉及到討論異步控制器的使用場合, 如果對異步控制器何時使用仍然糾結的同學, 這次可能會讓你們失望了, 不過關于這方面的討論和分析其實蠻多的, 大家也可以自行搜索.好了,廢話少說,上正文.
異步控制器
在MS越來越提倡異步操作的時代, ASP.NET MVC中的異步操作卻一直顯得比較落伍, 對于開發(fā)人員來說, 實現一個異步控制器往往要比普通的控制器花費更多的代碼. 這個特性是在ASP.NET MVC 2中被引入的, 之后就沒怎么改過,直到現在, 隨著C# 5和 async/await的即將到來, 異步控制器現在已經跟普通的控制器操作代碼一樣的簡練啦. 現在(當然得等ASP.NET MVC4,.NET 4.5和C# 5正式的發(fā)布之后), 你可以寫出下面這樣簡潔的代碼啦:
- publicasync Task<ViewResult> FooBar() {
- returnView(await DoSomething("Some Action"));}
怎樣? 真的是很簡單的吧~~
展望固然重要, 不過在這之前, 也請大家隨著我來回顧下一步控制器在ASP.NET MVC 2到4中的實現, 對比往往更能讓人印象深刻.
注意:下面關于ASP.NET MVC 4的例子都是基于ASP.NET MVC Developer Preview. 在正式版中, 這種實現可能會有所變化.
在ASP.NET MVC 2/3中的異步控制器
在ASP.NET MVC 2/3 中, 要實現一個一步控制器,你將不得不實現兩個方法, 一個叫XXXAsync, 另外一個叫XXXCompleted, 同時你的控制器還要改成繼承自AsyncController, 關于這個的實現和講解已經有很多現成的例子, 這里我就直接從MSDN上搬過來一個例子吧.
要看異步控制器, 我們首先看看同樣功能的同步實現, 大家應該都很熟悉了:
- publicclassPortalController: Controller{publicActionResult News(stringcity){
- NewsService newsService = newNewsService();
- ViewStringModel headlines = newsService.GetHeadlines(city);
- returnView(headlines);}
- }
我們再來看其異步實現方式:
- publicclassPortalController : AsyncController{
- publicvoidNewsAsync(stringcity){
- AsyncManager.OutstandingOperations.Increment();
- var newsService = newNewsService();
- newsService.GetHeadlinesCompleted += (sender, e) =>{AsyncManager.Parameters["headlines"] = e.Value;AsyncManager.OutstandingOperations.Decrement();};
- newsService.GetHeadlinesAsync(city);
- }
- publicActionResult NewsCompleted(string[] headlines){
- returnView("News", newViewStringModel{NewsHeadlines = headlines});}
- }
看看上面的實現, 不得不承認, 相對同步控制器, 異步Action開發(fā)人員要做的工作還是要多一些的. 但在.NET4.0的大環(huán)境中, 我們也只能用這種方式來實現了.
當然, MSDN的例子是標準的分層的實現例子, 在這個例子中,你將不得不實現自己的Service層, 如果你只是想簡單的調用異步Action, 有沒有方便的辦法呢? 答案是有的, 在.NET 4.0中,微軟帶來了Task類, 感興趣的同學可以猛擊這里. 有了Task,如果你只是想簡單的一個函數里面做異步操作也是可以滴:
- publicclassPortalController : AsyncController {publicvoidNewsAsync(stringcity)
- {AsyncManager.OutstandingOperations.Increment();
- var task = Task.Factory.StartNew(() => RunThread(city));
- task.ContinueWith(t =>{AsyncManager.Parameters["headlines"] = t.Result;
- AsyncManager.OutstandingOperations.Decrement();})
- ;}
- publicActionResult NewsCompleted(string[] headlines){
- returnView("News", newViewStringModel{NewsHeadlines = headlines});}
- privatestringRunThread(stringinput){
- Thread.Sleep(5000);returninput;}}
當然, 代碼并沒有減少太多, 不過也算是一種不太復雜的實現, 雖然沒那么好看, 但也不至于太難看.
下面我們再來看看ASP.NET MVC 4中的異步控制器吧.
ASP.NET 4 Developer preview中的異步控制器
在拋棄了對.NET 3的支持之后, ASP.NET MVC 4 徹底擁抱了Task類庫, 你不需要再蛋疼的給每個Action寫兩個方法, 也無需傻傻的手動對異步Action計數器增減了(AsyncManager.OutstandingOperations.Increment()), 現在的你只需拿起手指, 輕輕敲幾下, 其他的事情都由系統幫你完成.
- publicclassPortalController : AsyncController {
- publicTask<ViewResult> News( stringcity) {
- returnTask.Factory.StartNew(() => RunThread(city)).ContinueWith(t => {
- returnView(newViewStringModel(){Text = t.Result});
- });}
- privatestringRunThread(stringinput){
- Thread.Sleep(5000);
- returninput;}
- }
是不是好多了?Lamda可以讓一切更爽:
- publicTask<ViewResult> News(stringcity) {
- returnTask.Factory.StartNew(() => RunThread(city)).ContinueWith(t => View(newViewStringModel{
- Text = t.Result }));
- }
那么, 是不是到這里就要說再見了呢? 不是的, 請繼續(xù)往下看.
偉大的async/await
雖然還未到正式發(fā)布的時候, 不過如果我們跟著微軟的目光往前更進一步, 在ASP.NET和C# 5中, 或者我們從這里可以給.NET 4增加Async 的功能, 在有了async和await這兩個關鍵詞之后, 異步編碼就更簡單啦, 這其中也包括異步控制器的相關操作:
- publicclassPortalController : AsyncController {
- publicasyncTask<ViewResult> News(string city)
- {returnView(newViewStringModel(){
- Text = awaitNewThread(city)});}
- privateasync Task<string>NewThread(stringinput)
- { Thread.Sleep(5000);
- returninput; }}
總結
由于有了async和await關鍵字以及Task類庫的幫助, 在可預見的未來里, 我們操作異步控制器就可以像操作普通的控制器一樣了, 但就像其他的眾多新增的.NET特性一樣, 能力越大, 責任也就越大, 方便也往往意味著濫用. 異步控制器固然好, 但也并非每種場合都適合用它, 不恰當的使用它往往會導致服務器需要在不同的線程之間切換, 而這也帶來了更多額外的開銷. 在開發(fā)領域, 我們尤其要注意性能往往比其他任何東西都重要, 因此, 請在確實能提高性能和用戶相應的情況下使用異步控制器.
原文鏈接:http://www.cnblogs.com/jujusharp/archive/2012/02/02/async-controller-from-net-mvc-2-to-4.html
【編輯推薦】