MVC、wepabi允许使用Area(区域),每个Area代表一个模块。每个模块均可以有Controll、Model、View等等。
但是,如果不同的Area存在着相同的Controll/Action,就会对路由表造成混乱。
- 创建一个Area后,编译器就会自动创建一个文件AreaNameRegister.cs
namespace AreaDemo.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方法中定义了一个路由(访问此区域的路由)。
注意: Application_Start()中,AreaRegistration.RegisterAllAreas()和RouteConfig.RegisterRoutes(RouteTable.Routes)的调用顺序要注意。因为路由匹配的时候是有顺序的,如果调用顺序相反,就会匹配到错误的路由。
测试:
1. RouteConfig.RegisterRoutes(RouteTable.Routes)和AreaRegistration.RegisterAllAreas()顺序不变,在Area和外部定 义同名的Controll和Action,其他不变。
结果如下:
2.同测试1,只是在定义外部路由时RegisterRoutes,添加上 namespaces constrain
- 如果在Area中定义的Controller和Action与其他的Area相同的话基于要十分注意了,很可能会让路由表迷糊。
- 在Application_Start()中,调用AreaRegistration.RegisterAllAreas(),此方法会搜索所有的继承自AreaRegistration的类。
public class RouteConfig
{
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[]{ "AreaDemo.Controllers" }
);
}
}
运行正常。
3. 将AreaRegistration.RegisterAllAreas()和 RouteConfig.RegisterRoutes(RouteTable.Routes);函数顺序调换。执行结果如下:
访问外部路由正常,但是访问Area内部同名路由时报错:
结论:如果不加上constrain,路由匹配的时候,Area和外部的路由表可能会造成冲突。(如果有同名的控制器/方法就可能匹配到多个路由。正如测试1结果所示。)
其次,路由表匹配是有顺序的,如测试2和3所示。如果先注册Area中的路由,在匹配外部的路由。那么,当浏览器发送请求时,会先匹配到Area中的路由(如果两处的路由模板相近),但是实际上Area和外部的路由是不可能相同的,所以,即使匹配到Area中的路由,但是最后还是找不到对应的action,最终报错