【发布时间】:2011-06-19 22:21:59
【问题描述】:
我正在为一个需要支持多语言 URL 的新项目制定概念。理想情况下,所有 URL 都需要使用用户的母语。所以我们不想使用 domain.com/en/contact 和 domain.com/es/contact 但我们喜欢 domain.com/contact 和 domain.com/contactar(contactar 是西班牙语的联系方式)。在内部,两者都应该路由到同一个 ContactController 类。
这可以通过为每种语言添加多个静态路由到 Global.asax.cs 来处理,但我们希望使其非常动态,并希望系统用户能够更改 URL 的翻译内容管理系统。所以我们需要某种从 URL 到控制器和动作的动态映射。
通过查看MVC3的源代码,我发现MvcHandler的ProcessRequestInit方法负责确定创建哪个控制器。它只是在 RouteData 中查找以获取控制器的名称。覆盖默认 MVC 路由的一种方法是创建一个使用自定义 RouteHandler 的简单默认路由。这个 RouteHandler 强制 MVC 使用我自己的自定义子类版本的 MvcHandler 覆盖 ProcessRequestInit 方法。这个被覆盖的方法将我自己动态找到的控制器和操作插入到 RouteData 中,然后再回调原始 ProcessRequestInit。
我试过这个:
Global.asax.cs
routes.Add(
new Route("{*url}", new MultilingualRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Default", action = "Default" })
}
);
MultilingualRouteHandler.cs
public class MultilingualRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MultilingualMVCHandler(requestContext);
}
}
MultilingualMvcHandler.cs
public class MultilingualMVCHandler : MvcHandler
{
public MultilingualMVCHandler(RequestContext context) : base(context)
{
}
protected override void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
if (RequestContext.RouteData.Values.ContainsKey("controller"))
{
RequestContext.RouteData.Values.Remove("controller");
}
if (RequestContext.RouteData.Values.ContainsKey("action"))
{
RequestContext.RouteData.Values.Remove("action");
}
RequestContext.RouteData.Values.Add("controller", "Product");
RequestContext.RouteData.Values.Add("action", "Index");
base.ProcessRequestInit(httpContext, out controller, out factory);
}
}
在这个处理程序中,我将用于测试目的的控制器和动作硬编码为一些固定值,但将其变为动态并不难。它可以工作,但唯一的问题是我必须修改 ASP.NET MVC3 的源代码才能使其正常工作。问题是 MvcHandler 的 ProcessRequestInit 方法是私有的,因此不能被覆盖。我已经修改了源代码并将其更改为受保护的虚拟,这允许我覆盖它。
这一切都很好,但可能不是最好的解决方案。我总是需要分发我自己的 System.Web.Mvc.dll 版本,这很麻烦。最好能与 RTM 版本一起使用。
我是否错过了任何其他挂钩到 ASP.NET MVC 的可能性,它允许我根据 URL 动态确定要启动的控制器和操作?我想到的另一种方法是在 *Application_Start* 上动态构建 RouteCollection,但我认为这会使动态更改它变得更加困难。
如果我还没有找到任何关于钩子的提示,我将不胜感激。
【问题讨论】:
标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-routing