从之前的文章已经可以看到ASP.NET mvc路由系统的可配置和可扩展优点。如果这些都还没能满足你的要求,那你完全可以自定义ASP.NET MVC 路由系统的行为。下面我分别通过Route Base和Route Handler的方法来说明在ASP.NET MVC中自定义路由的方法。
一、自定义一个RouteBase的实现,截获ASP.NET MVC的请求
如果你不喜欢ASP.NET MVC默认、标准的URL匹配方式,你可以继承类RouteBase重写GetRouteData和GetVirtualPath方法来控制ASP.NET MVC对URL匹配,参数的获取,链接的生成。
RouteBase的两个方法:
GetRouteData(HttpContextBase httpContext):这个方法是用来根据请求的Url的获取路由信息,然后ASP.NET MVC框架会来依次调用所有注册的路由规则(RouteTable.Routes)的每一个节点,直到其中一个返回非空(non- null)值。
GetVirtualPath(RequestContext requestContext, RouteValueDictionary values):这个方法是用来生成链接信息,然后ASP.NET MVC框架会来依次调用所有注册的路由规则(RouteTable.Routes)的每一个节点,直到其中一个返回非空(non- null)值。
为了演示自定义一个RouteBase的场景,我们举一个例子:假如有一个系统已经运行了一段时间了,最近对系统进行了一次升级可能有的页面的URL地址有了变化,但他又要求要原来老的URL地址(/articles/Windows_3.1_Overview.html)能够正常的访问,因为用户可能把原来老的URL地址放到了收藏夹保存了起来,如果因为升级他们原来的URL不能访问了,会带来很多麻烦。
为了满足上面的要求我们需要一个Controller来接受原来老的URL。
- using System.Web.Mvc;
- namespace URLsAndRoutes.Controllers {
- public class LegacyController : Controller {
- public ActionResult GetLegacyURL(string legacyURL) {
- return View((object)legacyURL);
- }
- }
- }
- @model string
- @{
- ViewBag.Title = "GetLegacyURL";
- Layout = null;
- }
- <h2>GetLegacyURL</h2>
- The URL requested was: @Model
- using System;
- using System.linq;
- using System.Web;
- using System.Web.Mvc;
- using System.Web.Routing;
- namespace URLsAndRoutes.Infrastructure {
- public class LegacyRoute : RouteBase {
- private string[] urls;
- public LegacyRoute(params string[] targetUrls) {
- urls = targetUrls;
- }
- public override RouteData GetRouteData(HttpContextBase httpContext) {
- RouteData result = null;
- string requestedURL =
- httpContext.Request.AppRelativeCurrentExecutionFilePath;
- if (urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase)) {
- result = new RouteData(this, new MvcRouteHandler());
- result.Values.Add("controller", "Legacy");
- result.Values.Add("action", "GetLegacyURL");
- result.Values.Add("legacyURL", requestedURL);
- }
- return result;
- }
- public override VirtualPathData GetVirtualPath(RequestContext requestContext,
- RouteValueDictionary values) {
- return null;
- }
- }
- }
上面定义了一个字符串数组来存储老的URL,并通过构造函数来传入这个类能够处理的全部Url,然后在方法GetRouteData内判断当前url是否属于老的URL,如果是就新建一个RouteData实例并给controller和action赋值,也就是把请求定向到LegacyController中的Action,GetLegacyURL,最返回一个RouteData的实例,告诉MVC框架找到对应的RouteData信息,停止往下找匹配的路由结点。如果不是老的URL,就返回null,控制权交给MVC框架,继续往下找匹配的路由结点,直到找到一个返回为非null的RouteData。
最后,注册我们自定义的Route Base到ASP.NET 框架路由系统。
- public static void RegisterRoutes(RouteCollection routes) {
- routes.Add(new LegacyRoute(
- "~/articles/Windows_3.1_Overview.html",
- "~/old/.NET_1.0_Class_Library"));
- routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
- new { controller = "Home", action = "Index", id = UrlParameter.Optional });
- }
执行结果:
通过利用重写RouteBase,为controller和action变量赋值就可以在ASP.NET MVC中实现以.html结尾的伪静态。具体请看我之前的文章:教你如何在asp.net mvc中实现高性能以html结尾的伪静态
二、自定义一个Route Handler
方法一中在GetRouteData方法中是有下面一行代码:
- result = new RouteData(this, new MvcRouteHandler());
- using System.Web;
- using System.Web.Routing;
- namespace URLsAndRoutes.Infrastructure {
- public class CustomRouteHandler : IRouteHandler {
- public IHttpHandler GetHttpHandler(RequestContext requestContext) {
- return new CustomHttpHandler();
- }
- }
- public class CustomHttpHandler : IHttpHandler {
- public bool IsReusable {
- get { return false; }
- }
- public void ProcessRequest(HttpContext context) {
- context.Response.Write("Hello");
- }
- }
- }
上面CustomHttpHandler固定返回一个CustomHttpHandler实例,CustomHttpHandler每次接收到请求都返回一个字符串“Hello”。
最后,告诉MVC框架使用我们自定义的CustomRouteHandler。
- public static void RegisterRoutes(RouteCollection routes) {
- routes.Add(new Route("SayHello", new CustomRouteHandler()));
- routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
- new { controller = "Home", action = "Index", id = UrlParameter.Optional });
- }
三、总结
上面通过简单的实例通过Route Base和Route Handler的方法来说明在ASP.NET MVC中自定义路由的方法,最后都是在注册路由的里面插入了我们写的类,可以达到截获MVC的路由请求,控制路由匹配和请求返回特定内容效果。注意:MVC注册路由是有先后顺序的,所以我们自定义的类是要写在默认路由的前面。