_ __ _ __ _ ____ 更新 __ _ 的__ _ __ _ ___
从不同角度进行处理以解决自定义ControllerFactory的问题,请参阅下面的答案。
_ __ _ ____ 原始问题 __ _ __ _ __
我有一个用于多品牌部署的MVC代码库。为了满足每个客户的需求,我们设置了可覆盖的控制器和视图。
路线注册看起来像这样
protected void Application_Start()
{
string deploymentName = GetDeploymentName();
RouteConfig.RegisterRoutes(RouteTable.Routes, deploymentName);
}
在RegisterRoutes中,我们首先在部署命名空间中查找匹配的控制器,如果没有找到,请查看基本命名空间。
如果我们为每个部署设置了单独的IIS应用程序,这可以正常工作,因为每个部署都会执行自己的Application_Start()
但是,我们正在尝试在一个IIS站点中运行所有部署。这意味着Application_Start()只被调用一次,只为第一次部署注册路由才能被命中。
我正在尝试将RegisterRoutes从Application_Start()移到Session_Start()或Application_PreRequestHandlerExecute()
之类的东西protected void Application_PreRequestHandlerExecute()
{
string deploymentName = GetDeploymentName();
using (RouteTable.Routes.GetWriteLock())
{
RouteTable.Routes.Clear();
RouteConfig.RegisterRoutes(RouteTable.Routes, deploymentName);
}
}
使用此代码,每个请求都会获取当前部署命名空间,清除路由表,并使用新命名空间再次注册路由。
2个问题:
1:请求仍然根据PREVIOUS路由执行。所以我处于生命周期的错误部分,因为此时的请求已经注定要用于特定的控制器和操作。
2:下一个请求将抛出异常:
异常详细信息:System.InvalidOperationException:多个类型 被发现匹配名为'Home'的控制器。如果这可能发生 为此请求提供服务的路由('{controller} / {action} / {id}') 没有指定名称空间来搜索匹配的控制器 请求。如果是这种情况,请通过调用a来注册此路由 带有“名称空间”参数的'MapRoute'方法的重载。
即使我已取消注册以前的路由,应用程序似乎仍然挂在以前注册的控制器上,现在我已经注册到另一个同名控制器的另一个路由,两者之间存在歧义控制器。
我的两个主要问题是:
1。除了Application_Start()之外,是否还有其他生命周期事件可用于在请求已解析为先前存在的路由之前注册新路由?
2。如何完全清除路径和控制器,以便我不会因先前注册的控制器而出现歧义异常?
答案 0 :(得分:2)
我说这一切都错了......我不应该担心路线,我应该担心控制器实例化。我发现你可以在Application_Start()中用自己的自定义工厂替换controllerFactory:
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory(domainNamespaces));
所以这里我将带有命名空间值的域密钥字典传递给我的自定义控制器工厂中的构造函数
然后在工厂中我覆盖了查找控制器类型
的方法public class CustomControllerFactory : DefaultControllerFactory
{
public Dictionary<string, string> DomainNamespaces { get; set; }
public CustomControllerFactory(Dictionary<string, string> domainNamespaces)
: base()
{
DomainNamespaces = domainNamespaces;
}
protected override Type GetControllerType(RequestContext requestContext, string controllerName)
{
controllerName += controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ? String.Empty : "Controller";
string requestDomain = requestContext.HttpContext.Request.Url.Host;
string defaultNamespace = "API.Controllers.Base";
string deploymentNamespace = "API.Controllers.Deployments." + DomainNamespaces[requestDomain];
Assembly asm = Assembly.GetExecutingAssembly();
Type deploymentMatch = null;
Type defaultMatch = null;
foreach (Type type in asm.GetTypes())
{
if (type.Namespace == deploymentNamespace && type.Name.Equals(controllerName, StringComparison.OrdinalIgnoreCase))
{
deploymentMatch = type;
}
else if (type.Namespace == defaultNamespace && type.Name.Equals(controllerName, StringComparison.OrdinalIgnoreCase))
{
defaultMatch = type;
}
}
return deploymentMatch ?? defaultMatch;
}
}
答案 1 :(得分:1)
如果您在一个实例中运行所有内容而两个用户正在打开会话,那么哪条路由仍在注册,因为他们都在浏览您的网站?
您可以编写处理当前上下文的自定义路由,而不是在上下文更改时注册新路由:MVC 3 use different controllers based on request parameters