DefaultControllerFactory 為預設 Controller 工廠,核心挑戰在於從路由解析出的 Controller 名稱(不分大小寫、可能含命名空間通配符)正確匹配到實際 CLR 型別。本文詳細解析其反射掃描、命名空間匹配與型別解析邏輯,並提供自訂 ReflectionControllerFactory 模擬實現。
ControllerBuilder.DefaultNamespaces 可能含通配符 *BuildManager.GetReferencedAssemblies() 所有編譯引用組件IController 的型別,建立型別快取清單RouteData 取得 Controller 名稱與命名空間清單InvalidOperationExceptionpublic class ReflectionControllerFactory : IControllerFactory
{
private static List<Type> controllerTypes;
static ReflectionControllerFactory()
{
controllerTypes = new List<Type>();
foreach (var asm in BuildManager.GetReferencedAssemblies())
controllerTypes.AddRange(asm.GetTypes().Where(t => typeof(IController).IsAssignableFrom(t)));
}
public IController CreateController(RequestContext requestContext, string controllerName)
{
var controllerType = GetControllerType(requestContext.RouteData, controllerName);
if (controllerType == null) throw new HttpException(404, "No controller found");
return (IController)Activator.CreateInstance(controllerType);
}
private static bool IsNamespaceMatch(string requested, string target)
{
if (!requested.EndsWith(".*", StringComparison.OrdinalIgnoreCase))
return string.Equals(requested, target, StringComparison.OrdinalIgnoreCase);
var prefix = requested.Substring(0, requested.Length - 2);
return target.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) &&
(target.Length == prefix.Length || target[prefix.Length] == '.');
}
// GetControllerType 完整實現略...
}
RouteData.DataTokens["UseNamespaceFallback"] 若為 false,僅使用路由註冊命名空間;若為 true(預設),再嘗試 ControllerBuilder.Current.DefaultNamespaces。此機制支援區域註冊與全域預設命名空間協作。