• 初探MVC路由


    文章目录:

       1、认识理解URL,以及简单的路由

       2、特性路由、传统路由、区域路由

       3、路由生成URL&&绑定到操作&&路由约束

    1、认识理解URL,以及简单的路由

     默认简单的路由(概述、路由&URL重写)

      先来看下两个名词 URL(统一资源定位符),URI(统一资源标识符)

      高质量URL应该满足的规则:域名便于记忆和拼写、域名简短、便于输入、反映出站点的结构、“可破解的”,用户可以通过移除URL的末尾,进而到达更高层次的信息体系结构,持久不能改变

    路由概述:

      asp.net mvc 的路由主要有两种用途 1、匹配传入的请求,并把这些请求映射到控制器操作。2、构造传出的URL,用来响应控制器的操作

    路由&URL重写

      它们的共同点是都可以为搜索引擎优化,构建漂亮的URL,不同的是URL重写试讲一个URL映射到另外一个URL,路由关注的是将URL映射到资源;路由使用它的映射规则匹配传入的URL帮助生成URL,URL重写只能用于传入的URL,不能帮助生成原始的URL。

    2、特性路由、传统路由、区域路由

    特性路由:

      让我们来看下什么是特性路由,首先创建一个MVC项目,来到网站的入口点Global.asax文件,会看到在Application_Start 方法里面,存在一个方法 RouteConfig.RegisterRoutes(RouteTable.Routes);这个方法是集中控制路由的地方,这个方法对应着RouteConfig.cs文件的RegisterRoutes方法,因为我们要测试特性路由,因此我们把代码这样:

    public static void RegisterRoutes(RouteCollection routes)
    {
        //routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
        //routes.MapRoute(
        //    name: "Default",
        //    url: "{controller}/{action}/{id}",
        //    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        //);
        routes.MapMvcAttributeRoutes();
    }

    路由的核心工作是将一个请求映射到一个操作。静态路由,接下来,我们在Home控制器下的About方法上面使用一个特性

    [Route("about")]
    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";
    
        return View();
    }

    那当我们URL为about的时候、特性路由就会运行Home控制器的about方法,如下图所示:

    例如我们的首页,想要由多个匹配规则全都能匹配到,这时候就可以如此定义特性路由

    [Route("")]
    [Route("index")]
    [Route("home/index")]
    public ActionResult Index()
    {
        return View();
    }

    路由值

    例如我们现在要根据一个人的Id查询这个人的一些信息,此时Id作为参数传入,我们可以这样定义路由

    [Route("person/{id}")]
    public ActionResult Details(int id)
    {
        //Query person
        return View();

    我们的URL为person/1时候,就会访问到Details方法,参数Id值为1。也就是说当特性路由匹配并运行操作方法时,模型绑定会使用路由的路由参数为同名的方法参数填充值

    控制器路由

    我们可以使用特殊的路由参数"action"来匹配某个控制器下所有的方法

    [Route("home/{action}")]
    public class HomeController : Controller
    {
        //other action
    }    

    我们可以使用RoutePrefix 特性仅在一个地方制定路由开头

    [RoutePrefix("home")]
    [Route("{action}")]
    public class HomeController : Controller
    {
        [Route("")]
        [Route("index")]
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";
    
            return View();
        }
    
        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";
    
            return View();
        }
    }

    此时访问URL /index 和 /home/index就会如下结果

    加入我们想直接访问Home控制器的Index方法,我们就可以在Index方法上面添加以下特性路由,这样我们的URL 为/,/home,/home/index就都可以访问到Index方法了

    [RoutePrefix("home")]
    [Route("{action}")]
    public class HomeController : Controller
    {
        [Route("~/")]
        [Route("")]
        [Route("index")]
        public ActionResult Index()
        {
            return View();
    }

    路由约束:

    例如我们现在控制器里面有两个方法来查找一个人=》

    [Route("person/{id}")]
    public ActionResult Details(int id)
    {
        //Query person
        return View();
    }
    [Route("person/{name}")]
    public ActionResult Details(string name)
    {
        //Query person
        return View();
    }

    此时会发现,无论我们的URL 为/person/1 还是/person/bob 都能被[Route("person/{name}")]匹配到,这是我们的特性路由就存在二义性,这时候我们需要给路由添加一个约束,如下图所示,这样/person/1就会被匹配到[Route("person/{id:int}")] 这个路由,这种约束叫做“内联约束”。

    [Route("person/{id:int}")]
    public ActionResult Details(int id)
    {
        //Query person
        return View();
    }
    [Route("person/{name}")]
    public ActionResult Details(string name)
    {
        //Query person
        return View();
    }

     传统路由

     接下来我们来看一下传统路由,首先,修改RouteConfig 文件中的RegisterRoutes方法,如下所示

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "{controller}/{action}");
    }

    MapRoute方法的第二个参数我们称他为路由模板。路由模板和特性路由相同,是一种匹配规则,目的是将URL链接到操作方法,它们两者的不同点是完成这个操作传统路由依赖于名称字符串,特性路由依赖于特性。

    例如现在, 我们的请求URL 为/home/index,根据mvc的约定,mvc 会把Controller 添加到{controller}的参数后面,然后请求{action} 方法。

    路由值

    我们的路由除了必须的{controller} 和 {action} 参数以外,还可以存在第三个参数,例如下面的代码,我们的RouteConfig方法,我们的路由模板存在{id}这样一个参数,我们称它为路由值,当我们请求URL :/Person/Details/1的时候,该请求会导致MVC实例化PersonController类,调用Details方法,并将1传递给Details方法中的参数Id。

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "{controller}/{action}/{id}");
    }                 

    例如我们想让所有请求都用site/开头,我们就可以这样定义路由模板。

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "site/{controller}/{action}/{id}");
    }                 

    路由模板定义非常灵活,但是允许连续定义两个路由参数,例如这样就是错误的:{controller}{action}/{id};

    路由默认值:

    当我们的路由规则是 {controller}/{action}/{id} 这样的时候,我们要相匹配Person/Index是匹配不到的(因为不存在Id参数),这是我们需要重新定义我们的路由,给MapRoute方法添加第三个参数

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "{controller}/{action}/{id}"
            ,new { id=UrlParameter.Optional}); 
    }                 
    new { id=UrlParameter.Optional}这段代码定义了参数{id}的默认值,参数{id}为可选参数,当然我们也可以定义默认的控制器和方法,如下:
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "{controller}/{action}/{id}"
            ,new {controller="Home", action = "index", id=UrlParameter.Optional});
    }                 

    路由约束:

    当我们要请求这样一个控制器方法的时候,就可以使用路由约束。由于路由是从上往下匹配,当我们第一个路由规则匹配成功后,就不再往下匹配,所以,当我们请求URL为/2012/01/01时候,就会被第一个规则匹配到,进入到Home 控制器的Contact方法,当我们请求URL类似/Home/Index/123的时候,就会被第二个路由规则匹配到。

    public ActionResult Contact(int year,int month,int day)
    {
        ViewBag.Message = "Your contact page.";
    
        return View();
    }
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("home", "{year}/{month}/{day}"
            ,new {controller="home", action = "contact", id=UrlParameter.Optional}
            ,new { year =@"d{4}", month = @"d{2}", day= @"d{2}" });
        routes.MapRoute("simple", "{controller}/{action}/{id}");
    }                 

    当然我们可以一起使用特性路由和传统路由,如下所示

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapMvcAttributeRoutes(); //把特性路由放在传统路由的上面,URL优先匹配特性路由
        routes.MapRoute("home", "{year}/{month}/{day}"
            ,new {controller="home", action = "contact", id=UrlParameter.Optional}
            ,new { year =@"d{4}", month = @"d{2}", day= @"d{2}" });
        routes.MapRoute("simple", "{controller}/{action}/{id}");
    }                 

    在RouteConfig 的RegisterRoutes方法中,是可以给路由命名的,如下所示,我们使用mvc为我们提供的razor html标签(就是htmlHelper对象。。)的时候可以指定使用那个路由规则进行匹配,如下所示:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "{controller}/{action}/{id}"
                , new { controller = "Home", action = "index", id = UrlParameter.Optional });
        routes.MapRoute("home", "{controller}/{action}/{id}"
                 , new { controller = "Home", action = "about", id = UrlParameter.Optional });
    }                 
    @{
        ViewBag.Title = "Index";
    }
    
    <h2>Index</h2>
    
    @Html.RouteLink(
        linkText: "route home",
        routeName: "home",
        routeValues: new { controller = "Home", action = "index", id = 123 })
    @Html.RouteLink(
        linkText: "route simple",
        routeName: "simple",
        routeValues: new { controller = "Home", action = "about", id = 123 })

    区域路由

    mvc2.0 引入区域概念,可以将我们的网站划分为若干个节点,如下所示,我们添加了一个区域,在这个区域中,也存在一个叫做Home的控制器和Index的方法。然后我们访问这个网站,就会这样。。

    这个时候,我们需要给项目的路由指定一组用来定位控制器类的名称空间

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute("simple", "{controller}/{action}/{id}"
                , new { controller = "Home", action = "index" ,id =UrlParameter.Optional}
                ,new[] { "MVCSummary.Controllers" });
    }                 

    catch-all 参数,我们如下定义路由模板,{*extrastuff}被称为catch-all 参数参数,catch-all 参数可以匹配任意段的URL,但是只能作为路由模板的最后一段

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapMvcAttributeRoutes();
        routes.MapRoute("simple", "{controller}/{action}/{id}/{*extrastuff}"
                , new { controller = "Home", action = "index" ,id =UrlParameter.Optional}
                ,new[] { "MVCSummary.Controllers" });
    }                 

    3、路由生成URL&&绑定到操作&&路由约束

     路由除了能匹配传入的请求URL意外,还有一个重要的职责就是生成URL。

    路由的核心是RouteCollection基类RouteBase基类。

    RouteCollection类有两个重载方法GetVirtualPath,第一个方法传入请求上下文,和用户指定的路由值(一个字典),路由集合通过这个方法遍历每个路由匹配路由模板,假如匹配成功,则返回一个VirtualPathData对象,该对象包含生成的URL实例和用户定义的路由集合,见下图:

    第二个GetVirtualPath方法要求传入一个Routename, 它不会挨个遍历路由集合、假如找不到这个名称的路由或者匹配失败,就会返回空值,不再进行匹配。找到这个路由匹配成功则会返回一个VirtualPathData对象。

    整个URL的生成如下图所示:

    解释个名词,溢出参数:URL生成过程中使用但是没有在路由定义中指定的路由值。 例如我们的请求URL为/Home/Index/1?Page=1 ,这里的Page=1就是溢出参数

    接下来让我们看几个Route类生成URL的例子

    routes.MapRoute("report",        //这是我们的路由模板
        "{year}/{month}/{day}",
        new { controller = "Home", action = "Index", day = 10 });
    //调用Url.RouteUrl
    @Url.RouteUrl(new { param1 = value1, paraml2 = value2,..., paramlN = valueN });
    参数 返回URL 说明
    year=2017,month=12,day=08 /2017/12/08 直接匹配模板
    year=2017,month=12 /2017/12  day默认为10
    year=2017,month=12,day=08,Page=10 /2017/12/08?Page=10 Page溢出参数
    year=2007 null 参数不足,匹配失败

    路由绑定操作&自定义约束

    路由是如何绑定到操作的呢,如下图所示:

    在ASP.NET MVC中,MvcHandler实现了IHttpHandler接口,用来实例化控制器,并调用控制器上面的方法。

    路由数据:RouteCollection的GetRouteData方法会返回一个RouteData实例,这个实例里面包含了匹配请求的路由信息。当外界URL匹配成功时,它就创建一个字典用来保存路由参数,这个字典为Values,例如当路由模板为{controller}/{action}/{id} ,请求URL 为/Home/Index/123 则Values字典中应至少包含三个键controller、action、id,它们的值分别为Home、Index、123;特性路由的字典保存在DataTokens这个字典用。

     自定义约束:


    路由提供了一个接口IRouteConstraint ,这个接口有一个Math方法,当路由匹配完模板之后,假如有约束实现了IRouteConstraint接口,就会导致路由引擎调用Math方法,来确定是否满足给定请求。

    例如我们想要一个只实现Get请求的路由,HttpMethodConstraint继承自IRouteConstraint接口。

     routes.MapRoute("getmap", "{controller}", null, new { httpmethod = new HttpMethodConstraint("Get") });
  • 相关阅读:
    我倾向于使用发布版本进行调试,而不是使用调试版本
    常见WinDbg问题及解决方案
    在崩溃转储中查找所有可能的上下文记录
    向C/C++程序员介绍Windbg 脚本
    VS 使用技巧(1)
    Windows资源监视器软件的原理
    微架构、指令集架构与汇编语言的关系
    调试寄存器 原理与使用:DR0-DR7
    如何学习调试?
    WinDbg: 执行 SOS 扩展命令 !clrstack时报错 Access violation exception (0xC0000005)
  • 原文地址:https://www.cnblogs.com/liumengchen-boke/p/7968062.html
Copyright © 2020-2023  润新知