架構師對MVC設計模式的理解
我們目前正在開發中的是任務管理系統,一個前端複雜的專案,所以我們先從MVC講起吧。
WebForm
隨著ASP.NET MVC的興起,WebForm已成昨日黃花,但我其實還很想為WebForm說幾句。
沒有經歷過從ASP向ASP.NET轉變的同學,是很難理解當WebForm出現時,程式猿世界的歡呼雀躍的。事實上,我也是在Razor出現之後,才勉勉強強的轉向MVC,因為看見這個東西就怕。我曾經參加過一個升級ASP到ASP.NET的專案,ASP裡面亂七八糟的程式碼看得我眼睛又酸又脹紅通通的流淚,一輩子都記得!
最後生成的html可能會臃腫難看,但其內碼表面(.aspx)是相當清爽漂亮的。
既然我們都已經決定採用MVC了,WebForm的不足就不用再多說了。但我們應該努力的學習和借鑑它優秀的地方,這些也是在MVC的開發中會用到的:
呈現和頁面邏輯相分離。WebForm裡由於它的框架本來就顯式的區分了aspx和aspx.cs,所以大多數時候我們不會擔心這個事情。但MVC裡面,我們很容易就在view裡面利用ViewModel資料進行運算,模糊Controller和View之間的邏輯界限。這個問題我們將在CurrentUser的時候詳細講解。
少有人用。所以封裝和重用有一個度的問題。
RouteTest
Route功能是MVC的一個重大突破,也是一個重要缺陷。由於沒有良好的自動檢查機制,在實際的開發過程中,非常容易出錯!相信有過開發經驗的同學都有體會,有時候老半天都報錯:找不到View找不到Action,查來查去就一個拼寫錯誤;有時候新增一條RouteConfig,一會兒其他同事叫起來了,“考!原來是你的設定把我的覆蓋了。查了我一下午!”
把時間浪費在這些地方實在是可惜,所以我們解決這個問題的辦法是使用單元測試,在PCTest的project中引入了RouteTest。每一次新增RouteConfig,跑一遍單元測試:自己的能過,也不影響別人的,就OK了。
我們專案的UI層最成功的例子。照理說,MVC的最大的一個好處就是“可測試”,其他地方也應該廣泛引入單元測試的,但本人偷懶,另外HttpContext的sealed限制也限制了單元測試的實施(MVC 5應該解決了這個問題),所以目前UI層的單元測試還沒有展開。但估計這個工作遲早都得做,現在已經出現了一些手工測試繁瑣費事易遺漏的問題了。
URL/View層級
MVC現目前的另一個問題是,View很難按多層級組織。
注意Controller也有層級關係設定。我始終覺得這樣會更清晰整潔,但如果MVC的框架不能這樣進行“層級對應”。如果一定要這樣把View分層組織起來,在Action中就必須寫出View的全部路徑,比如:
public class LogController : Controller { // // GET: /Account/Log/On public ActionResult On() { return View("~/Views/Account/Log/On.cshtml"); } }
還得專門配置RouteConfig,這也太麻煩了一點。所以,我們就還是儘量按MVC的框架,從URL的設計開始,就儘量是/{Controller}/{action}/{route-parameter}的樣式,View也同樣,放在Contoller對應的資料夾下即可。
Partial/ChildAction/EditorTemplate
當我們需要重用某些“頁面片段”時,我們就面臨了以上這幾種選擇。切入的點有很多,我們就只結合我們專案,抽取其最鮮明最容易辨認的特點,直接講述他們的使用場景:
首先是EditorTemplate。它的特點最明顯,是和Post相關的。也就是,當一個“頁面片段”的資料,還需要再Post回伺服器的時候,我們就必須使用EditorTemplate;如果不使用EditorTemplate,就ViewModel的資料就無法傳回(參考:任務管理系統程式碼中/Views/Task/EditorTemplates)。為什麼呢?和MVC的ViewModel繫結機制有關,EditorTemplate中的html控制元件呈現時,會在其name上加上所屬父Model的字首,以便於MVC自動解析post資料並繫結到ViewModel。
如果“頁面片段”不需要POST,只負責呈現即可,又該如何選擇呢?我們的原則是:
如果“頁面片段”不需要和伺服器端互動,所需要的資料都能從父Model中獲得,使用Partial;
否則,如果“頁面片段”說需要的資料還需要從伺服器獲得,那就只能使用ChildAction了。
HtmlHelper
除了上述幾種頁面片段的重用,還有透過建立HtmlHelper的擴充套件方法,自定義一種“頁面片段”的呈現方式。這種方式一般是PartialView的一種替代方式,我們通常把“很小很小”(比如一個連結、一個下拉選單等),用處“很多很多”(甚至於跨專案)的可重用html片段用HtmlHelper封裝起來。可參考:
任務管理系統專案中的DocumentLink:封裝一個總是使用doc.zyfei.net域名的html連結
Global專案(還未上傳原始碼)中的EnumDropDownListFor:封裝一個使用dropdownlist,該dropdownlist由enum填充,使用enum上的[Description]作為呈現文字
AJAX
觀察我們的Action就可以發現,我們為Ajax提供的Action始終是返回的ActionResult,而不是使用“更先進”的WebApi機制(直接返回int等簡單型別)。這主要是因為我們使用了SessionPerRequest機制(主要是為了提高效能),我們讓一個Request請求只使用一個session(可先簡單的理解為一個資料庫連線),亦即:
當MVC獲得一個Request,需要使用session時,Service生成一個session;
然後,在這個Request的整個請求過程中,使用的都將是這個已經生成的session(類似於“單例模式”);
當Request結束後,釋放這個session,將所有改動同步到資料庫
好了,這裡我們的關鍵點就是什麼時候算“Request結束”?我們更進一步的定義它為View呈現完畢的時候,所以利用了Filter機制,在OnResultExecuted()時同步資料庫,程式碼如下:
public class SessionPerRequest : ActionFilterAttribute { public override void OnResultExecuted(ResultExecutedContext filterContext) { #if PROD FFLTask.SRV.ProdService.BaseService.EndSession(); #endif base.OnResultExecuted(filterContext); } }
所以,即使Ajax呼叫,也必須經歷一個“View呈現完畢”的過程,才能完成資料同步。
UIDevService切換
進行前臺開發,不需要連線後臺資料庫的同學,只需要在MVC專案編譯時,輸入UIDEV即可(如果要真正的連線資料庫,使用PROD),如下所示:
private IAuthroizationService _authService; public AuthController(IAuthroizationService authService) { _authService = authService; }
最後,在Global.asax.cs中我們透過條件編譯符if...else來確定究竟使用哪一種Service實現:UIDevServicemodule
void ResolveDependency() { var builder = new ContainerBuilder(); builder.RegisterControllers(Assembly.GetExecutingAssembly()); builder.RegisterFilterProvider();#if PROD builder.RegisterModule(new ProdServiceModule());#endif#if UIDEV builder.RegisterModule(new UIDevServicemodule()); #endif container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); }
最後,不要忘了,新引入一個Service時,在UIDevServicemodule.cs中新增:
builder.RegisterType().As ();
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2894/viewspace-2799947/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 架構師之路—理解設計模式架構設計模式
- MVC設計模式深入理解MVC設計模式
- 極簡架構模式-MVC模式架構模式MVC
- 理解Underscore的設計架構架構
- MVC、MVP、MVVM,談談我對Android應用架構的理解MVCMVPMVVMAndroid應用架構
- 架構設計思想-微服務架構設計模式架構微服務設計模式
- 架構師修煉之道(二)——架構?設計?架構師?架構
- 選用Vue做MVC架構模式VueMVC架構模式
- 架構師日記-深入理解軟體設計模式 | 京東雲技術團隊架構設計模式
- java架構師筆記:Java中的轉換器設計模式Java架構筆記設計模式
- Android 架構設計:MVC、MVP、MVVM和元件化Android架構MVCMVPMVVM元件化
- 系統架構設計師學習(二)系統架構設計師緒論架構
- Java程式設計師必備:微服務+開源框架+架構基礎+高效能架構+設計模式Java程式設計師微服務框架架構設計模式
- Tomcat 架構原理解析到架構設計借鑑Tomcat架構
- mvc架構MVC架構
- 系統架構設計師感想架構
- iOS架構設計:揭祕MVC, MVP, MVVM以及VIPERiOS架構MVCMVPMVVM
- iOS MVC、MVVM、MVP架構模式淺淺析iOSMVCMVVMMVP架構模式
- iOS架構入門 - MVC模式例項演示iOS架構MVC模式
- 阿里架構師Peter老師講述Java程式設計師→架構師所需要掌握的技能阿里架構Java程式設計師
- 好程式設計師前端教程-MVC框架的正確構建程式設計師前端MVC框架
- 膜拜阿里架構師全程手寫Spring MVC阿里架構SpringMVC
- 學習筆記-設計模式:MVC模式筆記設計模式MVC
- 軟體架構設計模式大全 - vikipediaaaa架構設計模式
- JAVA設計模式 5【結構型】代理模式的理解與使用Java設計模式
- 程式設計師、技術主管和架構師程式設計師架構
- .NET 雲原生架構師訓練營(設計原則&&設計模式)--學習筆記架構設計模式筆記
- 設計模式理解設計模式
- 理解設計模式設計模式
- 網際網路常用設計模式——通往架構師的第一步設計模式架構
- [譯]iOS架構模式——解密MVC、MVP、MVVM和VIPERiOS架構模式解密MVCMVPMVVM
- 說說你對前端架構的理解前端架構
- 架構師給程式設計師的一封信架構程式設計師
- 程式設計師與架構師之間的差距很大嗎?程式設計師架構
- Java程式設計師如何成為優秀的架構師Java程式設計師架構
- 10年資深架構師分享 | 普通程式設計師向架構師進階之路架構程式設計師
- “大話架構”阿里架構師分享的Java程式設計師需要突破的技術要點架構阿里Java程式設計師
- 利用WMRouter 重新架構設計業務模式架構模式