今天碰到了一个不可思议的bug,新增的controller中任何action都无法访问,都是返回404错误。一般这种错误要么是拼写错误,要么是不小心给action加了post属性,但是经过初步的排查,没有发现问题。而原有的controller中任何action都访问正常,新增的action也没有问题,但是换到新创建的那个controller中,问题就出现。于是问题定位在新增的那个controller中。于是翻开mvc的教程,仔细回顾了一下MVC中路由定位controller和action的过程,也没发现问题。最后仔细比对了一下代码,居然发现新旧controller的命名空间不一样,然后有查看了实现AreaRegistration的注册类iRecruiteAreaRegistration,只要controller的命名空间和iRecruiteAreaRegistration的命名空间一致的,都能正常寻找到action。
仔细看了一下MVC2中关于area注册路由的实现方式,确定area中的controller、action的路由跟命名空间是紧密联系在一起的。
MVC2中新增的area的路由也是在网站启动的时候注册的,即global的start方法中执行的,调用的方法是 AreaRegistration.RegisterAllAreas();这个方法遍历程序集中个继承了AreaRegistration类的类型,然后逐个调用这些类型的RegisterArea方法。一个常见的AreaRegistration类型如下。通常如果通过visual studio添加的area都自动生成了这个类。(我这里的area是手动生成的)。那么areaRegistration会关注哪些controller呢?实际上AreaRegistration类型会将其所在的命名空间保存在DataTokens["Namespaces"]中,在接收请求的时候就只会在这些命名空间或子空间中寻找controller,如果命名空间写错了,当然就无法识别了。因此实际上area注册仅仅起到的作用是,将area的名字和命名空间关联起来。因此如果要导航area中的controller必须首先提供area名字,这样就不会找到其他命名空间下的controller了。
文字描述比较多,具体可参考Apress.Pro.ASP.NET.MVC.2.Framework一书中Chapter8关于urls和routes的描述,非常的详细。
2 {
3 public class iRecruiteAreaRegistration : AreaRegistration
4 {
5 public override string AreaName
6 {
7 get
8 {
9 return "iRecruite";
10 }
11 }
12
13 public override void RegisterArea(AreaRegistrationContext context)
14 {
15 context.MapRoute(
16 "iRecruite_default",
17 "iRecruite/{controller}/{action}/{id}",
18 new { action = "Index", id = UrlParameter.Optional }
19 );
20 }
21 }
22 }