MVC自定义路由,实现二级域名类导致的找到多个与名为xxx的控制器匹配的类型的错误
今日在网站错误日志中发现手机站页面访问: http://m.jinrimianshi.com/company/395961
时出现找到多个与名为“company”的控制器匹配的类型。如果为此请求(“{controller}/{action}/{id}”)提供服务的路由没有指定命名空间以搜索与此请求相匹配的控制器,则会发生这种情况。如果是这样,请通过调用带有 'namespaces' 参数的 "MapRoute" 方法的重载来注册此路由的错误。
“company”请求找到下列匹配的控制器:
LMCMS.Areas.Admin.Controllers.CompanyController
LMSoft.Zhaopin.Controllers.CompanyController
我的m.jinrimianshi.com是自定义的二级域名,指向的是www.jinrimianshi.com的area=M的区域。在这里面只有一个home控制器,而没有company控制器。我感到有点奇怪,没找到相应控制器不是应该返回404错误么。
由于我没有使用namespaces参数,而有如果出现多个匹配,可以使用namespaces参数的maproute方法重载来注册此路由的提示。我进行了重写。重写后是这样得:
//自定义路由 routes.Add("DomainRouteForManage", new DomainRoute( "m.jinrimianshi.com", // 固定的二级域名 "{controller}/{action}/{id}", // URL with parameters new //defaults { area = "M", controller = "Home", action = "Index", id = UrlParameter.Optional, Namespaces = new string[] { "LMSoft.Zhaopin.Areas.M.Controllers" } } // Parameter defaults ));
但是编译刷新后问题依旧,没起什么作用。这时我想知道这个路由究竟是如何匹配的。由于以前处理路由匹配的时候知道有一个routedebugger工具可以查匹配情况。因此先装此工具。
首先在程序包控制台中执行命令
Install-Package routedebugger
执行后web.config中出现了一行代码:
<add key="RouteDebugger:Enabled" value="true" />
然后编译刷新项目,但是在页面底部并没有出现routedebugger的路由提示信息。经过分析,发现项目中缺少了对routedebugger的dll引用。在项目的packages包中找到routedebugger.dll,在项目中添加对其的引用。添加后编译,刷新项目,路由信息出现了。
通过查看,有4个匹配项。绿色为true的。由于我们知道mvc的路由匹配机制是从上往下寻找。当找到第一个匹配的时候就跳转到这个匹配规则上执行。下面的其他匹配被放弃。通过下图可以看出,确实匹配的是名字为DomainRouteForManage的自定义路由。可是已经限制了这个controller的命名空间为:LMSoft.Zhaopin.Areas.M.Controllers,怎么没起作用?
通过大量的查找资料,终于找到了想要的答案。原来在控制器的激活过程中,是由DefaultControllerFactory控制的。它首先在你限定的命名空间中进行查找,如果找不到相应的控制器,那么它会看DataTokens["UseNamespaceFallback"]是否有,如果没有设置,或者有但是值为true,那么在限定的命名空间中找不到相应的控制器的情况下,它会搜索项目中其他命名空间下的控制器,如果出现多个匹配,则就会报找到多个与名为“company”的控制器匹配的类型这样得错误信息。如果有设置,并且值为false,则在找不到匹配的情况下就会报404错误。那对应此次我碰到的错误。很显然,在LMSoft.Zhaopin.Areas.M.Controllers这个我限定的命名空间没找到名我company的控制器,而在DataTokens中,UseNamespaceFallback也没有。所以导致其搜索了项目其他命名空间的控制器,找到了两个匹配,因此出现了此错误。知道了错误的原因,那么解决此问题就有了思路。由于我自定义二级域名的路由使用的是一个自写的类:DomainRoute,此类是在网上找的,网上有相应代码,大同小异,我这里就不写了。我找到了此类中添加Namespaces的代码部分。
foreach (KeyValuePair<string, object> item in Defaults) { data.Values[item.Key] = item.Value;
#region 此处将area及Namespaces写入DataTokens里 if (item.Key.Equals("area") || item.Key.Equals("Namespaces")) { data.DataTokens[item.Key] = item.Value; }
#endregion
}
在data.DataTokens[item.Key] = item.Value;代码下面增加了一行代码:
data.DataTokens["UseNamespaceFallback"] = false;
由于这个是循环添加,加上后我还担心会不会重复添加UseNamespaceFallback,编译刷新后才发现自己多虑了。并没有重复添加,仍然是一个UseNamespaceFallback。
结果出来了,出现了我想要的,404未发现的错误。问题解决