前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ASP.NET MVC5高级编程 ——(5)路由

ASP.NET MVC5高级编程 ——(5)路由

作者头像
浩Coding
发布2019-07-03 10:55:00
2K0
发布2019-07-03 10:55:00
举报
文章被收录于专栏:浩Coding

这章呢,我们开始讲ASP.NET MVC5中的路由机制,在这之前,先提一下URL(Uniform Resource Locator)-- 统一资源定位符。需要注意的是,这里的“资源”这个词,是一个抽象的概念,既可以指一个文件,也可以指一个方法、一个类或是一段代码。由此我们引出了路由的主要用途

  • 匹配传入的请求(该请求不匹配服务器文件系统中的文件),并把这些请求映射到控制器操作。(controller/action--简单来说:Routing路由作用--确定Controller、确定Action、确定其他参数、根据识别出来的数据, 将请求传递给Controller和Action。)
  • 构造传出的URL,用来响应控制器操作

ASP.NET MVC5中有:特性路由和传统路由。

ASP.NET MVC5中的路由机制图解:

ASP.NET路由在两个地方设置:

1 :在应用程序Web.config文件中四个节点与路由有关:

sytem.web.httpModules,system.web.httpHandlers节,system.webserver.modules节,system.webserver.handlers节。

因为没有它们路由将不能工作。

2 :在应用程序的Global.asax文件中包含一个路由表,路由表在Application Start事件期间创建,当一个MVC应用程序首次运行时,会调用Application_Start()方法,这个方法随后调用RegisterRoutes()方法,RegisterRoutes()方法创建路由表

1.特性路由

1.1 路由URL

创建一个ASP.NET MVC Web应用程序项目后,浏览Global.asax.cs文件中的代码中,Application_Start方法中调用了一个名为RegisterRoutes的方法。该方法是集中控制路由的地方,包含在~/App_Start/RouteConfig.cs文件中。

代码语言:javascript
复制

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 } //默认值

);

}

修改RegisterRoutes方法中的内容,只通过调用MapMvcAttributeRoutes注册方式让RegisterRoutes方法启用特性路由。修改后的方法如下:

代码语言:javascript
复制
public static void RegisterRoutes(RouteCollection routes){
         routes.MapMvcAttributeRoutes();
}

路由的核心工作是将一个请求映射到一个操作。完成这项工作最简单的方法是在一个操作方法上直接使用一个特性:

代码语言:javascript
复制

//响应URL为 /about的请求

public class HomeController : Controller

{

[Route("about")]

public ActionResult About()

{

return View();

}

}

每当收到URL为/about的请求时,这个路由特性就会运行About方法。MVC收到URL,然后运行代码。

如果对于操作有多个URL,就可以使用多个路由特性。例如,想让首页可以通过/、/home和/home/index这几个URL都能访问,可以设置路由如下:

代码语言:javascript
复制
     //响应URL为 /、/home和/home/index三个URL

[Route("")]

[Route("home")]

[Route("home/index")]

public ActionResult Index()

{

return View();

}

传入路由特性的字符串叫做路由模版,他就是一个模式匹配规则,决定了这个路由是否是用于传入的请求。如果匹配,MVC就运行路由的操作方法。

1.2 路由值

对于简单的路由,适合刚才的静态路由,但并不是每个URL都是静态的。例如,如果操作显示个人记录的详情,则需要在URL中包含记录的ID。通过添加路由参数可解决这个问题:

代码语言:javascript
复制
     //id作为一个动态参数
    [Route("Person/{id}")]
    public ActionResult Details(int id){
       return View();
    }

通过花括号的id,就可以作为一个占位符。

多个占位符的情况可如下标识:

代码语言:javascript
复制
      //具有多个占位符
代码语言:javascript
复制

1.3 控制器路由

之前的讨论了如何把路由特性直接添加到操作方法上,但是很多时候,控制器类中的方法遵循的模式具有相似的路由模版,以HomeController控制器为例:

代码语言:javascript
复制

public class HomeController : Controller

{

[Route("home/index")]

public ActionResult Index()

{

return View();

}

[Route("home/about")]

public ActionResult About()

{

return View();

}

[Route("home/contact")]

public ActionResult Contact()

{

return View();

}

}

除了URL的最后一段,这些路由是相同的。所以期望能有一个方法能映射到home下的一个URL。

代码语言:javascript
复制

[Route("home/{action}")]

public class HomeController : Controller

{

public ActionResult Index()

{

return View();

}

public ActionResult About()

{

return View();

}

public ActionResult Contact()

{

return View();

}

}

使用控制器类的一个特性代替每个方法上的所有路由特性。在控制器类上定义路由时,可以使用一个叫做action的特殊路由参数,它可以作为任意操作名称的占位符。action参数的作用相当于每个操作方法上单独添加路由,并静态输入操作名:它只是一种更加方便的语法而已。

有时控制器上的某些具有与其他操作稍微不同的路由。此时,我们可以把最通用的路由放到控制器上,然后在具有不同路由模式的操作上重写默认路由。例如,如果我们认为/home/index过于冗长,但是又想支持/home,就可以如下:

代码语言:javascript
复制

[Route("home/{action}")]

public class HomeController : Controller

{

[Route("home")]

[Route("home/index")]

public ActionResult Index()

{

return View();

}

public ActionResult About()

{

return View();

}

public ActionResult Contact()

{

return View();

}

}

在操作方法级别指定路由特性时,会覆盖控制器级别指定的任何路由特性。在前面的例子中,如果Index方法只有第一个路由特性(home),那么尽管控制器有一个默认路由

home/{action},也不能通过home/index来访问Index方法。如果需要定义某个操作的路由,并且仍希望应用默认的控制器路由,就需要在操作上再次列出控制器的路由。

前面的类仍然带有重复性。每个路由都以home/开头(毕竟,类的名称是HomeController)。通过使用RoutePrefix,可以仅在一个地方指定路由以home/开头:

代码语言:javascript
复制

[RoutePrefix("home")]

[Route("{action}")]

public class HomeController : Controller

{

[Route("")]

[Route("index")]

public ActionResult Index()

{

return View();

}

public ActionResult About()

{

return View();

}

public ActionResult Contact()

{

return View();

}

}

现在,所有的路由特性都可以省略home/,因为前缀会自动加上home/。这个前缀只是一个默认值,必要时可以覆盖该行为。例如,除了支持/home和/home/index以外,我们还想让HomeController支持/。为此,使用~/作为路由模版的开头,路由前缀就会被忽略

在下面的代码中,HomeController的Index方法支持全部三种URL(/、/home和/home/index):

代码语言:javascript
复制
      //支持URL为 /、/home和/home/index

[RoutePrefix("home")]

[Route("{action}")]

public class HomeController : Controller

{

[Route("~/")]

[Route("")] //此处也可以简写 [Route]

[Route("index")]

public ActionResult Index()

{

return View();

}

public ActionResult About()

{

return View();

}

public ActionResult Contact()

{

return View();

}

}

1.4 路由约束

因为方法参数的名称正好位于由路由特性及路由参数名称的下方,所以很容易忽视这两种参数的区别。

对于这种情况,当收到/person/bob这个URL的请求时,根据路由规则,会将bob作为id参数传入,但bob无法转换为int类型,所以方法不能执行。

如果想同时支持/person/bob和/person/1,并且每个URL运行不同的操作,可以尝试添加具有不同特性路由的方法重载,如下所示:

代码语言:javascript
复制

[Route("person/{id:int}")]

public ActionResult Details(int id)

{

return View();

}

[Route("person/{name}")]

public ActionResult Details(string name)

{

return View();

}

因为传入的参数存在二义性,1也可以解释为字符串,因此需要添加int约束。路由约束是一种条件,只有满足该条件时,路由才能匹配。这种约束叫做内联约束。

内联路由约束为控制路由何时匹配提供了精细的控制。如果URL看上去相似,但是具有不同的行为,就可以使用路有约束来表达这些URL之间的区别,并把它们映射到正确的操作。

1.5 路由的默认值

代码语言:javascript
复制

[Route("home/{action}")]

public class HomeController : Controller

{

public Action Index()

{

return View();

}

}

对于以上代码,如果通过URL为 : /home进行访问,根据类定义的路由模版home/{action},以上代码不能运行。因为定义的路由只匹配包含两个段的URL,但是/home只包含一个段。

如果我们想让Index成为默认的action,路由API允许为参数提供默认值,代码如下:

代码语言:javascript
复制
[Route("home/{action=Index}")]
代码语言:javascript
复制
{action=Index}这段代码为{action}参数定义了默认值。此时,该默认情况就允许路由匹配没有action参数的请求。也就是现在既可以匹配具有一个段的URL,也可以匹配具有两个段的URL。
代码语言:javascript
复制
[Route("home/{action=Index}/{id?}")]

这段代码提供默认值Index,以及可选值id。

因为第二个段id是可选值,因此匹配的URL不再必须包含两个段。

2.传统路由

URL模式及模式匹配:

URL模式是路由系统的核心,相当于表示URL的一个公式。

URL模式的表现形式:{controller}/{action};

应用系统由若干条路由组织成,每条路由都有一个URL模式;

与模式匹配的URL可能有多条;

路由系统对应用的一个URL请求进行服务时,要查看这个URL请求与哪个URL模式相匹配,然后用这个模式对应的路由对这个URL请求进行处理;

URL匹配:

URL可以被分成除主机名(域名)和查询字符串以外的。以“/”分割的各个部分,每个部分是一个片段值

URL=http:// localhost/home/index

URL模式:{controller}/{action}

例子:

http:// localhost/home/index,Controller=home, action=index

http://mysite.com/admin/index, Controller=admin, action=index

例如: localhost/home/index,localhost是域名, 所以首先要去掉域名部分, 所以能够识别出 Controller=home, action=index, id没有则为默认值""。

Url路由实例讲解:

URL= /Home/Index/3 调用Index()方法,此时Id被忽略。

URL= /Home 调用Index()方法,并使用空字符串作为Id参数的值

URL= /Home/Index/3 调用Index()方法,id=“3”。

此时Index() 方法拥有一个可空整数参数。

URL= /Home 调用Index()方法,并使用 NULL 作为Id参数的值。

URL= /Home/Index/3 调用Index()方法,id=3。

URL= /Home 调用Index()方法,但会引发一个异常,因为id为null。

默认路由:

Routes.MapRoute(

"Default", // 路由名称

"{controller}/{action}/{id}", // 带有参数的URL

new { controller = "Home", action = "Index",

id = UrlParameter.Optional } // 参数默认值——默认路由

);

试想:如果不定义默认路由,URL将会如何进行匹配?

结论:只匹配与模式具有相同片段数的URL

带有静态片段(固定值)的URL:

routes.MapRoute( "", "hotels/{controller}/{action}", new { controller = "Hotel", action = "default"} );

例子:

http://myDemo.com/hotels/Home/index

http://myDemo.com/hotels/Hotel/default

Routes.MapRoute(“”,”X{controller}/{action}”);

例子:

http://myDemo.com/Xhome/index --(X就是固定值)

片段变量的访问:

使用RouteData.Values属性,可以在动作方法中访问任何一个片段变量。

Eg:“{controller}/{action}/{id}”

RouteData.Values(controller})

RouteData.Values(action})

RouteData.Values(id})

定义可选URL:

可选URL:用户不需要指定但又未指定默认值的片段。

Routes.MapRoute(

"Default", // 路由名称

"{controller}/{action}/{id}", // 带有参数的URL

new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 默认路由

);

匹配不管是否提供id的URL:URL= /Home 和URL= /Home/Index/3 都匹配。

定义可变长路由(任意长度的URL):

作用:能够在一个单一的路由中对任意长度的URL进行路由。

定义方法:通过指定一个叫做“catchall”的片段变量并以“*”作为其前缀,去除前面路径,后面所有的值都是catchall变量的值。

Eg:“{controller}/{action}/{id}/{*catchall}”

路由约束:

目的:实现对路由片段的值进行约束

方法:通过正则表达式、将一条路由约束到一组指定的值、约束使用HTTP方法的路由。

通过正则表达式约束路由:

routes.MapRoute

( "酒店列表页",

"hotels/{action}-{city}-{price}-{star}",

new { controller = "Hotel", action = "list", city = "beijing",

price="-1,-1", star="-1" },

new { city=@"[a-zA-Z]*",price=@"(\d)+\,(\d)+", star="[-1-5]"}

);

URL= localhost/hotels/list-beijing-100,200-3 ,会访问酒店频道的列表页,并传入查询参数。

将一条路由约束到一组指定的值:

通过“|”将指定的一组值分开,结合正则表达式使用:

Eg:routes.MapRoute ( “MyRoute",

“{controller}/ {action}/ {id}/{*catchall}",

new { controller = "Home", action = “index", id=

UrlParameter.Optional },

new { controller=“^H.*",action=“^Index$“|”^About$”}

); //只匹配action= Index或者About的路由

约束使用HTTP方法的路由:

目标:对匹配的URL使用的HTTP方法进行约束

Eg:routes.MapRoute ( “MyRoute",

“{controller}/ {action}/ {id}/{*catchall}",

new { controller = "Home", action = “index", id=

UrlParameter.Optional },

new { controller=“^H.*",action=“^Index$“|”^About$”}

httpMethod = new HttpMethodConstraint(“GET”)

); //把路由限制到GET请求

对磁盘文件的请求进行路由:

并不是MVC应用程序的所有请求都针对控制器和动作,MVC路由提供对内容进行服务。

服务开关:RouteCollection.RouteExistingFiles =true/false

Eg:routes.MapRoute ( “FileRoute”, “Content/test.html”,

new{controller=“Account”,action=“Logon”},

new{customConstraint = new UserAgentConstraint(“IE”)}

// 该路由把Content/test.html的URL请求映射到Account控制器的Logon动作方法, IE浏览器的用户将得到Account控制器的响应,而其他用户将看到test.html静态页面的内容。

Url路由实例讲解1:

Url路由实例讲解2:

生成输出URL的两种方法:在视图中生成(多数情况下)、在动作方法中生成。

在视图中生成输出URL:

在视图页面中通过调用ActionLink辅助器方法。

Eg:@Html. ActionLink(“链接文本”,”目标动作方法名”)

至于和哪个控制器进行绑定,取决于视图是通过哪个控制器的请求进行的渲染

可以用一个匿名类型为片段变量传递值

Eg:@Html. ActionLink(“链接文本”,”index”, new{id=“myId”})

在动作方法中生成输出URL:

Url.Action(“index”, new{id=“myId”})

Url.RouteUrl(new{controller=“home”,action=“index”})

RedirectToAction(“路由名称”)

URL匹配规则总结

(1)默认路由:

带静态片段的路由:

可选路由:

可变长路由:

(2)Routing规则有顺序(按照添加时的顺序), 如果一个URL匹配了多个Routing规则, 则按照第一个匹配的Routing规则执行

(3) {*values} 表示片段变量可以是任意的内容。

(4) 通过正则表达式等方法可实现自定义路由约束。

参考文章:

https://www.cnblogs.com/imstrive/p/6496187.html

本系列文章所有实例代码GitEE地址:

https://gitee.com/jahero/mvc

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浩Coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.特性路由
    • 1.1 路由URL
      • 1.2 路由值
        • 1.3 控制器路由
          • 1.4 路由约束
            • 1.5 路由的默认值
            • 2.传统路由
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档