应用场景:
ASP.NET MVC中,是依靠某些文件夹以及类的固定命名规则去组织model实体层,views视图层和控制层的。如果是大规模的应用程序,经常会由不同功能的模块组成,而每个功能模块都由MVC中的三层所构成,因此,随着应用程序规模的增大,如何组织这些不同功能模块中的MVC三层的目录结构,有时对开发者来说显得是种负担。
另一个问题就是Controller不允許有相同命名的存在,偏偏模块中常有父子关系,有时子模块命名相同就会造成错误。
幸运的是,ASP.NET MVC允许开发者将应用划分为“区域”(Area)的概念。
Area(区域)简介:
每个区域都是按照asp.net mvc的规定对文件目录结构和类的命名规则进行命名。添加方法也很简单,右击项目,点击添加区域,在弹出框里写上Area的名称点击确定即可。
1、新建 Area:右键 -> Add -> Area…
2、继承 AreaRegistration,配置对应此 Area 的路由
3、在 Global 中通过 AreaRegistration.RegisterAllAreas(); 注册此 Area
4、有了 Area,就一定要配置路由的命名空间
Area的路由
在添加好了区域之后,vs会自动帮我们注册Area的路由信息:
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 { controller = "Console", action = "Login", id = UrlParameter.Optional }
);
}
}
问题
试想如果这时候有这样的情形:
如果有一个Area叫CustomerManage,在它的下面有一个Controller名字叫做Customer。
另外我在顶层也有一个Controller,名字也叫Customer。
输入http://localhost:2024/CustomerManage/Customer,我们却能够正常地访问到DaleCloud.Web.Areas.CustomerManage.Controllers.CustomerController。原来在注册Area的路由时,如果没有填写命名空间的话,则会默认使用Area所在的命名空间。如此一来,使用Area的路由在寻找Controller时,只会在Area所在的空间下寻找相应的Controller。
那么我们在输入http://localhost/Customer,我们得到的将是一个异常:
错误提示: 找到多个与名为“Customer”的控制器匹配的类型。如果为此请求(“{controller}/{action}/{id}”)提供服务的路由没有指定命名空间以搜索与此请求相匹配的控制器,则会发生这种情况。如果是这样,请通过调用带有 ‘namespaces’ 参数的 “MapRoute” 方法的重载来注册此路由。
“Customer”请求找到下列匹配的控制器:
DaleCloud.Web.Controllers.CustomerController
DaleCloud.Web.Areas.CustomerManage.Controllers.CustomerController
个人理解:
根据RouteConfig的路由规则“{controller}/{action}/{id}”提供服务的路由没有指定命名空间,所以会匹配项目中所有命名空间下叫"Customer"的控制器,出现多个同名就会报错。
解决办法 :
在顶层路由映射的时候主动加上命名空间"DaleCloud.Web.Controllers"。 如果浏览器的URL符合RouteConfig的路由规则“{controller}/{action}/{id}",则它只会访问命名空间"DaleCloud.Web.Controllers"下面的控制器名。
再次访问 http://localhost:2024/CustomerManage/Customer 会匹配DaleCloud.Web.Controllers命名空间下的CustomerController。
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Customer", action = "Index", id = UrlParameter.Optional },// Parameter defaults
new[] { "DaleCloud.Web.Controllers" }// Namespaces 引入默认的命名空间
);
}
让起始页为某Area的页面:
修改RoutConfig代码:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Console", action = "Login", id = UrlParameter.Optional }
).DataTokens.Add("area","Admin");
}
注意后面的DataTokens.Add方法!
生成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>