asp.net MVC | 寻找.匹配Controller
最初以为是根据默认命名规范,从文件夹Controllers中查询 ^_^. 然后做了个测试,将controller放到新的工程.测试成功,程序可以运行.说明是从载入的程序集中搜寻controller的.难道是从所有加载程序集中搜寻匹配?同名的怎么办?
又做了一个测试.在新的命名空间OOne.Mvc.Controllers1创建HomeController(与默认生成的相同) ,
很不幸,结果程序显示以下错误:System.InvalidOperationException: The controller name 'Home' is ambiguous between the following types:
OOne.Mvc.Controllers.HomeController
OOne.Mvc.Controllers1.HomeController
行 16: HttpContext.Current.RewritePath(Request.ApplicationPath, false); |
源文件: D:"sl_projects"OOne"OOne.Mvc.View"Default.aspx.cs 行: 18
表面看来是在所有载入的程序集中查询.
然后查看mvc源代码,发现以下程序:
private Type GetControllerTypeWithinNamespaces(string controllerName, HashSet<string> namespaces) {
// Once the master list of controllers has been created we can quickly index into it
ControllerTypeCache.EnsureInitialized(BuildManager);
IList<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
switch (matchingTypes.Count) {
case 0:
// no matching types
return null;
case 1:
// single matching type
return matchingTypes[0];
default:
// multiple matching types
string typeNames = String.Join(", ", matchingTypes.Select(t => t.FullName).ToArray());
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
MvcResources.DefaultControllerFactory_ControllerNameAmbiguous,
controllerName, typeNames));
}
}
其中参数HashSet<string> namespaces 由以下语句生成:
RequestContext.RouteData.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj);
HashSet<string> nsHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
或者
HashSet<string> nsDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase)
或者
GetControllerTypeWithinNamespaces(controllerName, null /* namespaces */);
结论:
搜寻.匹配 是有优先级的. 首先会用 Route 注册时提供的 Namespace 进行匹配,在没有结果时再使用 ControllerBuilder.DefaultNamespaces 进行匹配.如果两者都没有, 就是匹配所有载入程序集内的controller了.
同级中找出来多个就错了!
附:
1. ControllerTypeCache ._cache 保存了所有载入程序集中的 Controller 类型
2. Route 注册 routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
, new String[] { "OOne.Mvc.Controllers1" } // namespace
);
3. DefaultNamespaces
protected void Application_Start()
{
//ControllerBuilder.Current.DefaultNamespaces.Add("OgilvyOne.Mvc.Controllers1");
RegisterRoutes(RouteTable.Routes);
}