為什麼需要分離?
我們知道mvc項目各部分職責比較清晰,相比較asp.net webform而言,mvc項目的業務邏輯和頁面展現較好地分離開來,這樣的做法有許多優點,比如可測試,易擴充等等。但是在實際的開發中,随着項目規模的不斷擴大,controller控制器也随之不斷增多。如果在controllers檔案夾下面有超過兩位數controller,即便采用良好的命名規範,或者用子檔案夾的形式區分不同功能的控制器,還是會影響項目的可閱讀性和可維護性。是以,在一些場景下,如果能把與某功能相關的檔案分離到一個獨立的項目中是非常有用的。asp.net
mvc提供了areas(區域)的概念達到這一目的。
一個典型的場景
web應用通常會有前台(面向使用者)和背景(面向管理者)兩部分,我們希望以/locahost/admin開始的url都為背景管理位址,是以我們也許會有這樣的路由:
1
2
3
4
5
6
7
8
9
10
11
<code>routes.maproute( </code><code>//admin route</code>
<code> </code><code>"admin"</code><code>, </code><code>// route name</code>
<code> </code><code>"admin/{controller}/{action}/{id}"</code><code>, </code><code>// url with parameters</code>
<code> </code><code>new</code> <code>{ controller = </code><code>"admin"</code><code>, action = </code><code>"index"</code><code>, id = urlparameter.optional } </code><code>// parameter defaults</code>
<code>);</code>
<code>routes.maproute( </code><code>//default route</code>
<code> </code><code>"default"</code><code>, </code><code>// route name</code>
<code> </code><code>"{controller}/{action}/{id}"</code><code>, </code><code>// url with parameters</code>
<code> </code><code>new</code> <code>{ controller = </code><code>"home"</code><code>, action = </code><code>"index"</code><code>, id = urlparameter.optional } </code><code>// parameter defaults</code>
運作程式通路locahost/admin, 通過routedebugger(asp.net
mvc路由調試的好幫手routedebugger)的輸出資訊可以看到,第一個路由(admin)比對成功,admincontroller的index方法被調用了,然而再仔細想想,通過/localhost/admin/index可以比對第二個路由(default),同樣可以調用admincontroller的index方法!以此類推,背景使用者管理清單(/localhost/admin/user/list)等同于(/localhost/user/list)。
第一次改進
我們要達到一種目的,那就是/localhost/admin/admin/index正确比對第一個路由,而/localhost/admin/index不比對第二個路由。是以可以對default路由進行條件限制,參考stephen walther的asp.net
mvc tip #30 – create custom route constraints,修改default路由為:
<code> </code><code>new</code> <code>{ controller = </code><code>"home"</code><code>, action = </code><code>"index"</code><code>, id = urlparameter.optional }, </code><code>// parameter defaults</code>
<code> </code><code>new</code> <code>{ controller = </code><code>new</code> <code>notequal(</code><code>"admin"</code><code>)}</code>
上面的路由意思是admincontroller不會比對default路由。現在分别運作之前的兩個url,會發現直接通路/admin/index已經不能比對到任何路由。通過修改notequal類,可以很容易為default路由添加多個“排除在外”的controller限制條件。但是,你不覺得這樣很挫麼?
第二次改進
這裡進入正題,使用areas這個功能來進行分離。建立一個項目"mymvcareasdemo",然後在項目上右鍵->添加->areas,輸入"admin",如下:

在areas/admin/controllers檔案夾下面建立homecontroller并添加一個index的方法和對應的view檔案。這裡可以發現areas的另一個好處:你可以在不同areas下面添加相同名稱的controller。當然,如果你直接這麼運作會得到一個錯誤:
這種情況需要修改一下adminarearegistration.cs和global.asax,分别為路由加上命名空間限制:
/areas/admin/adminarearegistration.cs
<code>context.maproute(</code>
<code> </code><code>"admin_default"</code><code>,</code>
<code> </code><code>"admin/{controller}/{action}/{id}"</code><code>,</code>
<code> </code><code>new</code> <code>{ action = </code><code>"index"</code><code>, id = urlparameter.optional },</code>
<code> </code><code>new</code> <code>string</code><code>[] { </code><code>"mymvcareasdemo.areas.admin.controllers"</code> <code>}</code>
<code> </code><code>);</code>
/global.asax.cs
<code> </code><code>"default"</code><code>, </code><code>// route name</code>
<code> </code><code>"{controller}/{action}/{id}"</code><code>, </code><code>// url with parameters</code>
<code> </code><code>new</code> <code>{ controller = </code><code>"home"</code><code>, action = </code><code>"index"</code><code>, id = urlparameter.optional }, </code><code>// parameter defaults</code>
<code> </code><code>new</code> <code>string</code><code>[] { </code><code>"mymvcareasdemo.controllers"</code> <code>}</code>
這樣,我們就可以把所有與背景管理相關的controller和view檔案放到/areas/admin下面,以此類推,可以添加諸如會員(member),部落格(blog),論壇(forum)等多個areas。各部分都有自己的頂層檔案夾,實體檔案都分離開來,管理起來比較友善。
這種方式已經有了很大提高,但是所有的檔案還是放在同一個項目裡面。當項目規模較大的時候,比較好的開發方式是将不同功能子產品按需要獨立到不同項目裡面,最後再整合成一個整體。這樣,每一個項目可以獨立開發,測試和釋出。
第三次改進
我們需要對現有項目進行一下改造:
1. 在解決方案上面建立一個mymvcareasdemo.admin的mvc3項目,并且删除global.asax和web.config兩個檔案
2. 在根目錄建立一個adminarearegistration的類,輸入如下内容:
12
13
14
15
16
17
18
19
<code>public</code> <code>class</code> <code>adminarearegistration : arearegistration</code>
<code>{</code>
<code> </code><code>public</code> <code>override</code> <code>string</code> <code>areaname</code>
<code> </code><code>{</code>
<code> </code><code>get</code>
<code> </code><code>{</code>
<code> </code><code>return</code> <code>"admin"</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>override</code> <code>void</code> <code>registerarea(arearegistrationcontext context)</code>
<code> </code><code>context.maproute(</code>
<code> </code><code>"admin_default"</code><code>,</code>
<code> </code><code>"admin/{controller}/{action}/{id}"</code><code>,</code>
<code> </code><code>new</code> <code>{ action = </code><code>"index"</code><code>, id = urlparameter.optional } </code>
<code> </code><code>);</code>
<code>}</code>
3. 删除mymvcareasdemo項目/areas/admin檔案夾下面的adminarearegistration.cs檔案以及controllers檔案夾(包括homecontroller)
4. 在mymvcareasdemo.admin項目的controllers裡面建立一個homecontroller
5. 記得保留mymvcareasdemo/areas/admin下面的views,并且在mymvcareasdemo項目裡面引用mymvcareasdemo.admin項目,如圖:
現在運作程式并通路/admin/home/index可以發現admin項目生效了。這樣,我們可以将所有的與背景管理相關的controller都放到這個新的項目中來。但是很快你會發現,一個新的“問題”又出現了:
當你在mymvcareasdemo.admin裡面的homecontroller添加新的action(例如list),然後習慣性在上面右鍵-"add view"後,你會發現新增的list.cshtml檔案會出現在mymvcareasdemo.admin/views/home下面,然後當你通路/admin/home/list的時候浏覽器會得到錯誤提示:"the view 'list' or its master was not found or no view engine supports the searched
locations…"。原來它隻會在主程式mymvcareasdemo中的對應目錄去尋找view。這麼一來,mvc架構提供給我們的腳手架功能就大打折扣,當然你可以手動在mymvcareasdemo/areas/admin/views中對應添加view,或者在mymvcareasdemo.admin項目中自動生成了view之後再拷貝過去。有沒有更好的辦法呢?
第四次改進
為了使我們在mymvcareasdemo.admin自動生成的view自動同步到mymvcareasdemo/areas/admin/views檔案夾中,可以使用“生成事件(build event)”裡的“post-build event”,打開mymvcareasdemo.admin的屬性,修改如下圖所示:
我本地的生成事件為:
<code>mkdir</code> <code>"$(solutiondir)$(solutionname)\areas\admin\views"</code>
<code>xcopy </code><code>"$(projectdir)views"</code> <code>"$(solutiondir)$(solutionname)\areas\admin\views"</code> <code>/s</code> <code>/e</code> <code>/c</code> <code>/y</code>
意思其實很簡單,相信大家都能看得懂,就是完全複制mymvcareasdemo.admin的views檔案夾下所有檔案至mymvcareasdemo/areas/admin/views中。
現在再次通路/admin/home/list就可以得到正确結果了,并且你可以發現list.cshtml已經被複制到mymvcareasdemo/areas/admin/views/home目錄裡。
至此大功告成!我們已經将面向前台和面向背景的子產品成功分離到兩個獨立的項目中,希望能對您有所幫助!
轉自:http://www.cnblogs.com/dingji/archive/2012/05/30/2506420.html