MVC模式中路由如何生成URL

时间:2022-09-11 16:18:07

路由有必要的参数吗

在MVC设计模式中,一个比较重要的步骤是浏览器发送的请求如何生成相应的URL,交给服务器去实例化相应的控制器类然后调用相应的控制器类的对应方法,返回视图给用户。这个流程细说起来比较复杂,这里只记录MVC如何根据用户请求去查询匹配的路由,然后生成相应的URL这一个处理过程。

在定义一个路由的时候,我们只需要在项目文件的App_Start文件夹下的RouteConfig类中操作即可。

public class RouteConfig
   {
       public static void RegisterRoutes(RouteCollection routes)
       {
           routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
               name: "test",
               url: "{controller}/{action}/{id}",
               defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },//默认值
               constraints: new {id=@"/d{3}" },//自定义约束
                namespaces: new string[] { });//匹配的路由需要实例化控制器类的命名空间

}
   }

在这段断码中,创建了一个名字是“test”的默认路由,里面的参数url为匹配格式,defaults是默认值,constraints是该路由参数的约束,   namespaces是匹配到路由后实例化控制器类时候该类的命名空间。指定命名空间可以减少MVC查找控制器类的时间和避免控制器类重名时出现的错误。因为实例化控制器的时候,程序会查找所有实现了IController接口的类,然后找到与用户匹配传入请求对应的控制器类,这个时候如果有两个同名的控制器类,就会出现错误,但是如果制定了命名空间,程序就会到该命名空间下查找控制器类,效率会有微小的提升,实例化该命名空间下的控制器类,避免了重名的情况。如果对MVC有了解,我们就会知道,诸如http://localhost/Home/Index/1  ; http://localhost/Admin/Index/   ;这样的URL将会匹配”test“ 路由。就拿http://localhost/Home/Index/1来说(参数1可能并不是必要的)。因为会匹配test路由,所以对应的控制器类是HomeController,方法是Index,参数是1.  但是他们是如何匹配的呢?接下来会详细记录匹配的过程。

路由的核心是一个非常简单的算法,该算法基于一个由RouteCollection类和一个RouteBase类组成的简单的抽象对象。首先看下路由是如何使用这些类的。尽管可以通过多种方法去生成URL,但是这些方法总是会以调用一个RouteCollection.GetVirtualPath的重载方法而结束。RouteCollection.GetVirtualPath有两个重载的方法。这两个重载方法的签名是:

public VirtualPathData  GetVirtualPath(RequestContext requestContext,RouteValueDictionary  values)

public VirtualPathData  GetVirtualPath(RequestContext requestContext,string name,RouteValueDictionary  values);

第一个重载版本第一个参数是接受当前请求的RequesContext,第二个参数是由用户指定的路由值(字典)

在这个过程中,该方法遍历路由字典的每一个路由并且询问”给你这种类型的参数,你能匹配到所有的参数,生成给定参数的URL吗“一旦有一个路由应答能够完成,那么该路由就会返回一个包含了URL的VirtualPathData实例以及其他匹配信息,否则就返回空值,路由表往下移动接着询问。

第二个重载版本,第二个参数是路由的名称,这里如果我们的请求匹配test这个路由,我们直接传入test,程序就会直接去从路由集合中查找test这个路由去匹配,(路由集合的路由不可能重名)。经过一系列逻辑匹配,如果匹配正确就跟第一个重载的方式一样,返回一个包含了URL的VirtaulPathData视力以及包含了其他匹配信息,如果不匹配,程序不会再遍历路由集合,而是直接返回空值。不再匹配其他的路由了。

当我们声明一个超链接的时候,可能会像下面这样声明@Html.ActionLink("测试","Index","Home",new {id=3})。这个方法会反过来调用RouteCollection.GetVirtualPath的方法,并向它传递一个RequestContext对象,一个包含值的字典以及用来生成URL路由名称去匹配超链接 Home/Inde/3这个请求。一旦在路由表中找到匹配这份链接的路由对象,该路由就会返回包含URL以及其他匹配信息的VirtualPathData实例对象,仔细观察test这个路由我们会发现,对于参数id有一个约束,这个约束会自动将字符串转换成正则表达式,如果id是三个整数则匹配,否则不匹配该路由。所以在匹配路由生成URL的时候也会检查约束。这整个过程也许通过一张流程图看起来会更加清晰。

MVC模式中路由如何生成URL

通过这张图片,可能会更加直观的看到,路由是如何生成URL的。总结一下。

1.用户发送诸如(http://localhost/Home/Index/1)这样的请求

2.调用RouteCollection.GetVirtualPath方法得到匹配路由,返回URL以及匹配信息(遍历路由表得到匹配路由)

然后在简单的看一下MVC请求的简单的管道过程

(1)UrlRoutingMoudle尝试使用在RouteTable中注册的路由匹配当前请求(具体匹配过程就是上面的过程)

(2)如果Routale中有一个路由成功匹配,路由模块就会从匹配成功的路路由得到实现了IRouteHandler接口的MVCRouteHandler实例对象;

(3)通过MVCRouteHandler对象的GetHandler()方法得到一个实现了IHttpHandler接口的MVCHandler实例对象。

(4)调用HTTP处理程序的ProcessRequest()方法,并将要处理的请求交给他

(5)通过以上得到了MVCHandler对象,这个对象主要用于实例化控制器类,并调用该实例化控制器类对象上的方法。