Mar*_*urg 4 asp.net-mvc asp.net-mvc-routing asp.net-mvc-3
我正在研究一个新项目的概念,我需要支持多语言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方法.在重新调用原始ProcessRequestInit之前,此重写方法将我自己动态找到的控制器和操作插入到RouteData中.
我试过这个:
的Global.asax.cs
routes.Add(
new Route("{*url}", new MultilingualRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Default", action = "Default" })
}
);
Run Code Online (Sandbox Code Playgroud)
MultilingualRouteHandler.cs
public class MultilingualRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MultilingualMVCHandler(requestContext);
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在这个处理程序中,我将控制器和操作硬编码为某些固定值,但是要使这种动态变化并不困难.它的工作原理但唯一的问题是我必须修改ASP.NET MVC3的源代码才能使它工作.问题是MvcHandler的ProcessRequestInit方法是私有的,因此无法覆盖.我修改了源代码并将其更改为protected virtual,这允许我覆盖它.
这一切都很棒但可能不是最好的解决方案.我总是需要分发我自己的System.Web.Mvc.dll版本,这很麻烦.它可以与RTM版本一起使用会好得多.
我是否遗漏了任何其他挂钩ASP.NET MVC的可能性,这将允许我动态确定控制器和要启动的操作,具体取决于URL?我想到的另一种方法是在*Application_Start*上动态构建RouteCollection,但我认为这将使得在运行中更改它变得更加困难.
我会很感激我还没有找到任何挂钩的提示.
现在这已经很老了,以防万一其他人正在寻找类似的东西......
除非我完全误解你想做什么,否则它真的很简单.
步骤1:向global.ascx.cs添加一个新路由,其中包含对您的个人路由引擎的引用
routes.Add(new MyProject.Routing.ContentRoutingEngine());
Run Code Online (Sandbox Code Playgroud)
确保它位于路由列表中的正确位置,以便其他路由引擎可以在需要时捕获其中的内容,或者如果引擎未处理特定路由则继续路径搜索.我把它放在忽略之后,但在MVC默认路由之前.
步骤2:创建内容路由引擎,确保它继承自System.Web.Routing.RouteBase抽象类,并根据需要覆盖GetRouteData和GetVirtualPath方法,例如
public class ContentRoutingEngine : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var routeHandler = new MvcRouteHandler();
var currentRoute = new Route("{controller}/{action}", routeHandler);
var routeData = new RouteData(currentRoute, routeHandler);
// set your values dynamically here
routeData.Values["controller"] = "Home" ;
// or
routeData.Values.Add("action", "Index");
// return the route, or null to have it passed to the next routing engine in the list
return routeData;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
//implement this to return url's for routes, or null to just pass it on
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
那应该这样做.您可以根据需要在引擎中动态更改路径,并且不需要更改MVC源.让标准MVC RouteHandler实际调用控制器.
后记:显然上面的代码不是生产标准 - 它的编写是为了尽可能明显地发生了什么.
| 归档时间: |
|
| 查看次数: |
2449 次 |
| 最近记录: |