天天看點

BrnShop開源網上商城第二講:ASP.NET MVC架構

  在團隊設計BrnShop的web項目之初,我們碰到了兩個問題,第一個是資料的複用和傳遞,第二個是大mvc架構和小mvc架構的選擇。下面我依次來說明下。

      首先是資料的複用和傳遞:對于BrnShop的每一次請求,程式都要分成好幾個階段執行,例如驗證,執行動作方法等等,在各個階段我們可能需要重複使用同一資訊,而我們的願景就是希望此資訊隻需擷取一次,然後沿着流程管道一直流動,這樣在後面的階段中就可以直接使用,不用再重新擷取了,提高程式的性能。舉例來說:在授權驗證階段,我們為對使用者進行驗證,進而擷取了使用者資訊,當驗證結束後,此使用者資訊并不被抛棄,而是保留下來,這樣在後面的動作方法中我們就不需要再次擷取使用者資訊,而是直接使用剛才在授權中保留下來的使用者資訊就可以了。

  具體實作是這樣的:首先我們給這些需要公用的資料定義個上下文類,它們分别是BrnShop.Web.Framework項目中的WebWorkContext類和AdminWorkContext類,其中WebWorkContext是前台項目使用的上下文,AdminWorkContext是背景項目使用的上下文。代碼很簡單,就是定義了一些公共字段,具體如下:

BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構

View Code

BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構

   有了上下文類後,我們需要找一個可以保證上下文流動的地方。在翻看了asp.net mvc的源碼後,我們找到一個好地方,這個地方就在控制器的基類Controller中。在Controller中微軟定義了六個方法,具體如下:

protected override void Initialize(RequestContext requestContext);說明:初始化調用構造函數後可能不可用的資料。

protected virtual void OnAuthorization(AuthorizationContext filterContext);說明:在進行授權時調用。

protected virtual void OnActionExecuted(ActionExecutedContext filterContext);說明:在調用操作方法後調用。

protected virtual void OnActionExecuting(ActionExecutingContext filterContext);說明:在調用操作方法前調用。

protected virtual void OnResultExecuted(ResultExecutedContext filterContext);說明:在執行由操作方法傳回的操作結果後調用。

protected virtual void OnResultExecuting(ResultExecutingContext filterContext);說明:在執行由操作方法傳回的操作結果前調用。

  這些都是虛方法,是以我們可以定義一個繼承自Controller的新控制器,然後重寫這些方法。由于這些方法是在同一個類中,是以它們可以共享同一個字段(這個字段就是上下文),而且其他的控制器都是繼承自這個新控制器類,是以在動作方法中也是可以通路這個共享字段(父類的字段)。新控制器類分别是BrnShop.Web.Framework項目中BaseWebController類和BaseAdminController類,其中BaseWebController為前台控制器類,BaseAdminController為背景控制器類,具體實作如下:

BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構

  到此事情還沒完,那就是這個上下文是控制器的字段,在視圖中如果想通路它需要強制類型轉換下,代碼為:((BaseWebController)(this.ViewContext.Controller)).WorkContext;試想一下我們每次通路上下文都需要這麼長的一段代碼那是怎樣的煎熬呀?不過幸好有解決辦法,那就是重寫mvc的WebViewPage頁(如果你不知道WebViewPage和mvc的編譯過程請閱讀大神“Artech”的相關文章,位址如下:http://www.cnblogs.com/artech/)。具體代碼在BrnShop.Web.Framework項目中WebViewPage類和AdminViewPage類,其中WebViewPage為前台視圖類,AdminViewPage為背景視圖類:

BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構
BrnShop開源網上商城第二講:ASP.NET MVC架構

   定義好新的視圖類後,我們需要通知編譯器使用這個新類,通知方式在視圖檔案的web.config中,具體見下圖:

BrnShop開源網上商城第二講:ASP.NET MVC架構

  通過将"pageBaseType"的值設定為我們的新類名,我們就可以在視圖檔案中直接使用上下文了。例:@WorkContext.ShopConfig.SEOKeyword

  說完了資料的複用和傳遞,我們再來說說大mvc架構和小mvc架構的問題。首先何為大mvc架構,何為小mvc架構?

大mvc架構指的是盡量完整的一套asp.net mvc架構,包含路由,控制器,模型綁定,模型校驗,篩選器等等。

小mvc架構指的是隻包含項目所必須使用的mvc部分,對于使用不到的部分盡量不用或移除。

  大家可能覺得這有什麼難的?但是對于一個開源項目來說這确實是一個很重要的問題,因為開源項目的産品面向的是全國甚至是全世界的開發者,大家的技術參差不齊,有的高,有個低。為了保證盡可能多的覆寫開發者,隻有原汁原味的mvc才對開發者更親切和熟悉,是以應該使用大mvc架構。可是一款優秀的産品不隻是面向初級開發者,還需要面對進階開發者,對于進階開發者來說他們希望獲得項目最大的可控權,是以架構應該盡量隻使用最核心的mvc部分,這樣留給開發者的空間才能更大,這樣這樣看來又應該使用小mvc架構。下面我從兩個方面來說明我們是如何解決這個問題的。

  首先是mvc篩選器:看過我們源碼的園友已經發現,我們項目中沒有定義任何一個篩選器類。那我們的篩選器在哪兒?答案就在上面的上下文流動中,在上面重寫的篩選器方法中我們實作所有篩選。如果你想針對某個控制器A單獨篩選你可以在A中再一次重寫篩選器方法添加自己的代碼。如果你想隻針對某一方法進行篩選你隻需要單獨在方法中篩選就可以了。這樣通過使用内置在controller中的篩選方法我們實作了和第三方篩選器的隔離,也減少了反射擷取篩選器的次數。

  其次是模型綁定和校驗:我們首先通過手動擷取request集合的方式去除所有模型綁定,以登陸代碼為例:

其次是模型校驗,校驗又分為兩部分。第一部分是驗證,對此我們也是采用手動校驗的方式,同樣以登陸為例:

通過上面代碼大家可以看出所有的驗證都是手動進行的。

  校驗的第二部分是驗證資訊顯示,在mvc中大家經常使用Html.ValidationMessageFor之類的方法來顯示驗證資訊,是以為了保證上述方法還能夠正常使用,我們需要将所有驗證資訊都添加到ModelState中(因為Html.ValidationMessageFor之類的方法實作本質就是通過擷取ModelState指定鍵值的内容來判斷是否顯示和顯示什麼内容)。到此我們已經有了校驗資料,剩下的就是在視圖中顯示了。關于顯示我們仍然可以使用Html.ValidationMessageFor之類的方法;如果你想獲得更大的靈活性你可以使用視圖頁面的“GetVerifyErrorList”方法,此方法在我們新定義的視圖基類中,它的功能就是将校驗資訊建構成一個json對象。代碼如下:

下面給出一個使用例子,代碼是登陸視圖的代碼:

  通過以上實作我們既保證架構能夠相容mvc各個功能,又為進階開發者提供了足夠的擴充空間。PS:團隊中有位同僚曾經将asp.net mvc源碼中有關模型綁定和模型校驗的代碼全部删除,并完美運作執行個體,性能和開銷都少了不少,有興趣的朋友可以去試試!