原文地址:ASP.NET MVC – Legacy Url Routing
原文作者:matthaw
本文地址:ASP.NET MVC – 旧形式URL的路由
本文作者:Q.Lee.lulu
最 近我们已经将大部分我们ASP.NET Web Form页面转换为使用ASP.NET MVC。当这个并不是一个小的工程的时候,使用一个新的URL结构并支持旧的URL是很有需要的。这个想法是,当你点击一个不存在的页面的时候,你会被定 位到MVC里面合适的Controller和Action中去。
流程
1. 一个来自你的网站的旧形式的URL请求.例如:http://www.server.com/Users/Login.aspx
2. ASP.NET routing 拦截这个请求并匹配你RouteCollection中的一个Route
3. 并不是使用 MvcRouteHandler, 而是 LegacyRouteHandler 被调用.
4. 使用 LegacyRouteHandler, 它将会使用你指定的Route重定向名来产生MVC URL,并发出一个定位到http://www.server.com/site/login的HTTP 301 请求.
Routing
首先,我们需要定义我们的旧版Route类。这是必需的,因为我们需要暴露一个额外的属性来允许我们的routing处理器来找到正确的MVC route。
// 旧形式URL的route类,暴露一个RedirectActionName public class LegacyRoute : Route { public LegacyRoute(string url, string redirectActionName, IRouteHandler routeHandler) : base(url, routeHandler) { RedirectActionName = redirectActionName; } public string RedirectActionName { get; set; } }
然后,我们需要定义route handler和关联的http handler。Route handler继承自IRouteHandler,而当创建你的旧形式URL routing的时候要使用这个类。Http handler继承自MvcHandler,因为它会为我们提供一些关键的信息,例如RequestContext。你也许会注意到你需要从 request上copy所有的querystring参数(代码中并没有写出来)。这是必需的一步,因为GetVirtualPath方法调用时会需要 所有的route data(来自RouteData.Values)并尝试利用它来创建URL。
// The legacy route handler, used for getting the HttpHandler for the request public class LegacyRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new LegacyHandler(requestContext) } } // The legacy HttpHandler that handles the request public class LegacyHandler : MvcHandler { public LegacyHandler(RequestContext requestContext) : base(requestContext) { } protected override void ProcessRequest(HttpContextBase httpContext) { string redirectActionName = ((LegacyRoute)RequestContext.RouteData.Route).RedirectActionName; // ... copy all of the querystring parameters and put them within RouteContext.RouteData.Values VirtualPathData data = RouteTable.Routes.GetVirtualPath(RouteContext, redirectActionName, RouteContext.RouteData.Values); httpContext.Status = "301 Moved Permanently"; httpContext.AppendHeader("Location", data.VirtualPath); } }
最后,你需要在Global.asax文件中创建你的routes。记住,在配置routing的时候这是必需的一步。
public void RegisterRoutes(RouteCollection routes) { routes.MapRoute("Login", "site/login", new { controller = "Users", action = "DisplayLogin" }); routes.Add("", new LegacyRoute( "Users/Login.aspx", "Login", new LegacyRouteHandler() )); }
就是这样。当一个请求来到的时候,你会在Fiddler中看到如下的信息:
- A request on "Users/Login.aspx"
- A HTTP 301, with a header "Location" and value of "site/login"
- A request on "site/login"
Final Thoughts
Granted, there's more you can do with this – like creating your own extension methods like MapRoute and doing better handling of finding the route, but this should get you started. Also, I'm writing the code off the top of my head, so there's no guarantee that any of it works as-is. Please let me know if you have any other thoughts.
Lastly, for those wondering why are we using a HTTP 301 status code? Well read up on them. "301 Moved Permanently" indicates "that all future requests should be directed to the given URI." While your end users will not see any difference other than a new URL in the browser, the 3