初探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") });
原文地址:https://www.cnblogs.com/liumengchen-boke/p/7968062.html