软件下载 | 资讯教程 | 最近更新 | 下载排行 | 一键转帖 | 发布投稿
您的位置:最火下载站 > 网络编程 > ASP.NET > ASP.NET MVC 1.0 Route Namespace

ASP.NET MVC 1.0 Route Namespace

在使用 MapRoute() 注册路由规则的时候,MVC 允许我们提供一些默认的 Namespace。那么这些 Namespace 究竟有什么作用呢?要搞清这个问题,我们首先要明白 MvcHandler 和 DefaultControllerFactory 如何创建 Controller 实例 (流程参考前面章节)。

public static class RouteCollectionExtensions
{
...
public static Route MapRoute(this RouteCollection routes, string name, string url,
string[] namespaces);
...
}

DefaultControllerFactory 通过 GetControllerType() 获得实际的 ControllerType,然后反射创建控制器实例。在 GetControllerType 方法中,我们看到两个步骤,首先会用 Route 注册时提供的 Namespace 进行匹配,在没有结果时再使用 ControllerBuilder.DefaultNamespaces。

public class DefaultControllerFactory : IControllerFactory
{
protected internal virtual Type GetControllerType(string controllerName)
{
...

// first search in the current route's namespace collection
object routeNamespacesObj;
Type match;
if (RequestContext != null && RequestContext.RouteData.DataTokens.TryGetValue("Namespaces",
out routeNamespacesObj))
{
IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
if (routeNamespaces != null)
{
HashSet<string> nsHash = new HashSet<string>(routeNamespaces,
StringComparer.OrdinalIgnoreCase);

match = GetControllerTypeWithinNamespaces(controllerName, nsHash);
if (match != null)
{
return match;
}
}
}

// then search in the application's default namespace collection
HashSet<string> nsDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces,
StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(controllerName, nsDefaults);
if (match != null)
{
return match;
}

// if all else fails, search every namespace
return GetControllerTypeWithinNamespaces(controllerName, null /* namespaces */);
}

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
// we need to generate an exception containing all the controller types
StringBuilder sb = new StringBuilder();
foreach (Type matchedType in matchingTypes)
{
sb.AppendLine();
sb.Append(matchedType.FullName);
}

throw new InvalidOperationException(
String.Format
(
CultureInfo.CurrentUICulture,
MvcResources.DefaultControllerFactory_ControllerNameAmbiguous,
controllerName, sb
)
);
}
}
}

这里面提到了 ControllerTypeCache,它的作用是缓存了所有的控制器的类型信息。

internal sealed class ControllerTypeCache
{
private Dictionary<string, ILookup<string, Type>> _cache;

public void EnsureInitialized(IBuildManager buildManager)
{
if (_cache == null)
{
lock (_lockObj)
{
if (_cache == null)
{
List<Type> controllerTypes = GetAllControllerTypes(buildManager);

var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
StringComparer.OrdinalIgnoreCase);

_cache = groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
}
}
}

private static List<Type> GetAllControllerTypes(IBuildManager buildManager)
{
// Go through all assemblies referenced by the application and search for
// controllers and controller factories.

List<Type> controllerTypes = new List<Type>();
ICollection assemblies = buildManager.GetReferencedAssemblies();

foreach (Assembly assembly in assemblies)
{
Type[] typesInAsm;
try
{
typesInAsm = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
typesInAsm = ex.Types;
}

controllerTypes.AddRange(typesInAsm.Where(IsControllerType));
}
return controllerTypes;
}

}

相关阅读
栏目导航
推荐软件