MVC提供Area機制,在同一個項目以內就可以切割出不一樣的ASP.NET MVC網站。html
插入:首先在相同的位置,好比說同一個文件夾(如:Controllers)是不能建立倆個相同名稱的文件(如:HomeController),其次在不一樣的文件夾中如fold1和fold2,中各自建立一個TestController,程序可以經過編譯,但當瀏覽器視圖執行/Test時,網站報出異常,如圖:瀏覽器
由於在默認狀況下,路由會同時匹配兩個controller,形成沒法訪問。ide
在項目上,右鍵,建立區域,問題解決。post
ASP.NET MVC容許使用 Area(區域)來組織Web應用程序,每一個Area表明應用程序的不一樣功能模塊。這對於大的工程很是有用,Area 使每一個功能模塊都有各自的文件夾,文件夾中有本身的Controller、View和Model,但對於管理也增長了必定的難度。url
建立Area
右鍵工程選擇 添加->區域,彈出以下填寫Area的對話框:spa
點擊添加後,工程目錄結構以下:code
和建立一個空MVC工程結構相似,Admin Area 有本身的 Controllers、Models 和 Views 文件夾,不同的地方就是多了一個 AdminAreaRegistration.cs 文件,這個文件中定義了一個叫 AdminAreaRegistration 的類,它的內容以下:htm
namespace MvcApplication1.Areas.Admin {
public class AdminAreaRegistration : AreaRegistration {
public override string AreaName {
get {
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context) {
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
}
系統自動生成的 AdminAreaRegistration 類繼承至抽象類 AreaRegistration,並重寫了 AreaName 屬性和 RegisterArea 方法。在 RegisterArea 方法中它爲咱們定義了一個默認路由,咱們也可在這個方法中定義專屬於Admin Area的的其餘路由。但有一點要注意,在這若是要給路由起名字,必定要確保它和整個應用程序不同。
AreaRegistrationContext 類的 MapRoute 方法和 RouteCollection 類的 MapRoute 方法的使用是同樣的,只是 AreaRegistrationContext 類限制了註冊的路由只會去匹配當前 Area 的 controller,因此,若是你把在 Area 中添加的 controller 的默認命名空間改了,路由系統將找不到這個controller 。
RegisterArea 方法不須要咱們手動去調用,在 Global.asax 中的 Application_Start 方法已經有下面這樣一句代碼爲咱們作好了這件事:
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
調用 AreaRegistration.RegisterAllAreas 方法讓MVC應用程序在啓動後會尋找全部繼承自 AreaRegistration 的類,併爲每一個這樣的類調用它們的 RegisterArea 方法。
注意:不要輕易改變 Application_Start 中註冊方法的順序,若是你把RouteConfig.RegisterRoutes方法放到AreaRegistration.RegisterAllAreas方法以前,Area 路由的註冊將會在路由註冊以後,路由系統是按順序來匹配的,因此這樣作會讓請求 Area 的 Controller 匹配到錯誤的路由。
Area的運行
在Area中添加controller、view和model和通常的添加是同樣的。在這,咱們在Admin Area中添加一個名爲 Home 的controller,代碼以下:
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
}
而後咱們再爲Index Acton添加一個View,代碼以下:
@{
ViewBag.Title = "Index";
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h2>Admin Area Index</h2>
</div>
</body>
</html>
運行應用程序,而後將URL定位到/Admin/Home/Index,下面是運行結果:
到這,咱們已經看到,Area中的的工做流程其實就是和根目錄下的流程是同樣的。但Area並非一個徹底獨立的工做空間,咱們下面來看看。
Controller的歧義問題
試想一下,若是咱們如今在根目錄的 Controller 文件夾中也添加一個名爲 Home 的 Controller,而後咱們經過把URL定位到 /Home/Index,路由系統能匹配到根目錄下的 Controller 嗎?
在根目錄的 Controllers 文件夾中添加好 HomeController 後,爲Index添加View,內容隨意:
...
<body>
<div>
<h2>Root Index</h2>
</div>
</body>
...
路由不改動,咱們使用 RouteConfig.cs 文件中系統定義的默認路由:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
運行程序,將URL定位到 /Home/Index。結果咱們會看到以下錯誤信息:
出現這個問題是由於路由系統進行匹配的時候出現了Controller同名的歧義。
當Area被註冊的時候,Area中定義的路由被限制了只尋找 Area 中的Controller,因此咱們請求 /Admin/Home/Index 時能正常獲得 MvcApplication1.Areas.Admin.Controllers 命名空間的 HomeController。然而咱們在RouteConfig.cs文件的RegisterRoutes方法中定義的路由並無相似的限制。
爲了解決這個問題,咱們須要在RouteConfig.cs文件中定義的路由中加上對應的 namespaces 參數。RouteConfig.cs 中修改後的路由以下:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "MvcApplication1.Controllers" }
);
}
運行程序,以下結果說明解決了同名歧義問題:
添加了 namespaces 參數後,路由系統在對這個路由進行匹配時,優先匹配指定命名空間的controller,若是匹配到則即刻中止查找,若是在指定的命名空間下沒有匹配到對應的controller,再按照通常的方式進行匹配。
生成Area URL連接
關於Area的URL連接生成,能夠分爲這麼三種狀況:第一種是在當前Area生成指向當前Area的連接;第二種是生成指向其餘Area的連接;第三種是在某個Area中生成指向根目錄的連接。下面是這三種狀況生成連接的方法,使用的路由定義是系統默認的。
若是要在Area中生成當前Area的URL連接,直接用下面的方法就行:
@Html.ActionLink("Click me", "About")
它根據當前所在的Area和Controller會生成以下Html代碼:
<a href="/Admin/Home/About">Click me</a>
若是要生成其餘Area的URL連接,則須要在Html.ActionLink方法的匿名參數中使用一個名爲area的變量來指定要生成連接的Area名稱,以下:
@Html.ActionLink("Click me to go to another area", "Index", new { area = "Support" })
它會根據被指定的Area去找路由的定義,假定在Support Area中定義了對應的路由,那麼它會生成以下連接:
<a href="/Support/Home/Index">Click me to go to another area</a>
若是要在當前Area生成指根目錄某個controller的連接,那麼只要把area變量置成空字符串就行,以下:
@Html.ActionLink("Click me to go to top-level part", "Index", new { area = "" })
它會生成以下Html連接:
<a href="/Home/Index">Click me to go to top-level part</a>
參考:《Pro ASP.NET MVC 4 4th Edition》