URL Routing
URL Routing模型是用来将浏览器输入的请求(requests)映射为MVC controller actions。
1、使用默认的Route表
当你创建ASP.NET MVC应用程序时,就已经配置为使用URL Routing的应用程序。URL Routing创建于两个地方。
一、在Web.config启用URL Routing。在Web.config文件中存在4个和Routing关联的sections,system.web.httpModules 、system.web.httpHandlers 、system.webserver.modules、 和system.webserver.handlers。
二、Route表创建于Global.asax文件中
public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start(){ RegisterRoutes(RouteTable.Routes);} }
对于这里参数如果不为空时,可以对应Action:Index(int id)和Index()。但是如果Action为:Index(int id)则传入的参数不能为空。
2、自定义URL Routing
创建一个匹配任何以/Archive/开头的Request的Route:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "blog", //自定义route必须出现在default之前,否则它不会被调用 "Archive/{entryDate}", //匹配任何以'/Archive/’开头的请求 new { controller = "Archive", action = "Entry" }); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); }
自定义route必须出现在默认Route之前。
3、MVC的URL Routing实现
ControllerBase类实现了IController接口,而该接口只提供一个方法void Execute(RequestContext)。RequestContext基的构造方法需要的参数类型HttpContextBase和HttpContext很相似。
public class RequestContext { public RequestContext(HttpContextBase httpContext, RouteData routeData); public HttpContextBase HttpContext { get; } public RouteData RouteData { get; } }
从这可以看出MVC中URL Routing介入的起始点就在RequestContext类。
public class RouteData { public RouteData(); public RouteData(RouteBase route, IRouteHandler routeHandler); public RouteValueDictionary DataTokens { get; } public RouteBase Route { get; set; } public IRouteHandler RouteHandler { get; set; } public RouteValueDictionary Values { get; } public string GetRequiredString(string valueName); }
RouteBase 类:
public abstract class RouteBase { protected RouteBase(); public abstract RouteData GetRouteData(HttpContextBase httpContext); public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values); }
要研究透URL Routing,首先就必须清晰上面RouteData类中提到RouteValueDictionary、IRouteHandler。Route初始化时使用RouteValueDictionary来加入默认值及规则到Route中,而IRouteHandler的则提供了一个GetHttpHandler方法来获取用于处理URL的IHttpHandler。其接口定义如下:
public interface IRouteHandler { IHttpHandler GetHttpHandler(RequestContext requestContext); }
GetHttpHandler输入参数是RequestContext ,而IHttpHandler 的ProcessRequest方法处理的参数则是HttpContext。这也就是URL Routing首次和HttpContext打交道的地方。如是实现这个转换呢?
//在构造方法中传入RequestContext 参数,用以设置页面RequestContext
public class MyPage:IHttpHandler { public RequestContext RequestContext { get; private set; } public MyPage(RequestContext context) { this.RequestContext = context; } #region IHttpHandler public virtual void ProcessRequest(HttpContext context) { //将访问页面如a_b_c_index.aspx转换为a/b/c/index.aspx context.Server.Execute(RequestContext.RouteData.Values["page"].ToString().Replace("_","/")+".aspx"); } public bool IsReusable { get { return false; } } #endregion }
//实现IRouteHandler public class MyRouteHandler : IRouteHandler { #region IRouteHandler public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new MyPage(requestContext); } #endregion }
这样我们就可以在Golbal.asax的Application_Start事件中写如下代码
RouteTable.Routes.Add(new Route("{page}.aspx",new MyRouteHandler()));