URL是Uniform Resource Locator的首字母缩写,名为统一资源定位符,主要负责定位查找Internet中的信息资源,是Internet上标准的资源地址。资源是个抽象的概念,既可以指某个文件也可以指某方法调用的结果,所以URL不仅可以包含了文件的信息,也可以携带参数。
URL主要由四部分组成,他们分别是传输协议、服务器地址、端口号、路径名,中间用“/”符号拼接:
传输协议指的是要访问的服务器的传输类型,如FTP(文件传输协议)、SMTP(电子邮件协议)、HTTP(超文本传输协议)、HTTPS(超文本传输安全协议)、DNS(域名系统协议)、TELNET(会话协议)等等,当然这里我们WEB指的是一般都是HTTP或者HTTPS。
服务器地址用来定位资源所存在的机器,在公网中每台服务器会分配一个唯一的IP地址,我们可以通过IP找到对应的服务器。
端口号连接时所使用的通信端口号,这是Internet用来辨别信息服务用的一种软件标识。因为一台服务器上可能部署多个服务,为了能更精准的当问到指定的服务我们就可以通过指定端口来区分。
路径名指的是指定资源的具体文件路径或者方法调用,由于资源不一定是文件,所以路径中常常会携带参数,在方法调用的时候进行传参。
ASP.NET MVC 路由是建立在Asp.NetFramework之上的组件,路由机制同样也可以应用在WebForms应用中,对于ASP.NET Web Forms来说,路由定位的是一个有效的文件。这个文件可以是静态的图片、视频等文件,也可以是.aspx动态页面。而对于ASP.NET MVC来说,路由则是指向了某个Controller类型中的Action方法,同时支持URL参数传递,这让路由属性更加灵活多变,可控性也强。
1,安全性高,避免直接访问物理资源,提高了系统的安全性;
2,灵活性强,URL不会因为物流资源的改变而改变;
3,可读性好,通过定义URL可以直观的知道访问的资源类型;
4,SEO优化,良好的URL规范容易被搜索引擎识别收录;
5,易重写,可以在不同的路由模式的操作上重写默认路由。
在创建一个新的ASP.NET MVC项目时在项目的根目录中生成一个Global.asax文件,它是一个全局文件也是项目运行时的初始函数,它的作用是全局注册组件,比如申明全局注册、Filters注册、 Route注册、Bundle注册等。项目启动时会自动调用Global.asax文件中的Application_Start方法,该方法中默认申明了全局注册及路由注册。
Application_Start方法则调用了RegisterRoutes的方法(这个方法在~/App_Start/RouteCOnfig.cs中被定义),用来向ASP.NET MVC 注册了路由规则,通过RouteCollection 的MapRoute方法(MVC提供MapRoute、MapPageRoute、IgnoreRoute三种方式)向系统增加一条路由规则,这个路由规则适用于所有的控制器。
name:路由的名称;
url:这是个路由匹配规则,告诉系统请求资源的路径,也就是我们URL中的路径名,这里每个部分用{}括起来,相当于占位符,是变量,用来申明URL中的每个组成部分;
defaults:这是个默认的对象,{}中的变量指向了固定的参数表示执行匹配,这里是告诉系统去Home Controller控制器中找Index方法并且传入id这个参数,因此我们必须保证在项目的Controllers文件夹中必须有一个叫做HomeController的对象且对象中必须有Index这个方法,否则在访问该路由时就会提示资源不存在,而Optional 是可选没有也可以。
有了以上配置就可以满足大部分的路由配置了,我们可以把更多的时间用在Model、View和Controller模块开发上,MVC 会自动去匹配每一个路由,直到找到匹配的路由并将请求映射到对应的action上,如果没有找到指定的路由就会弹出404错误提示。比如RouteCOnfig.cs中的defaults: new { controller="Home", action="Index", id=UrlParameter.Optional }就告诉我们当我们启动程序时默认执行HomeController控制器中的Index方法,向用户展示index.cshtml页面。如果Controller中不存在对应的控制器和方法时就会报“/”应用程序中的服务器错误。
特性路由就是利用特性去定义路由让你在应用程序中能更好的控制URL,特性路由可以简化URL和Action之间的映射关系。添加了特性路由后只能通过特性路由设置的路径访问,一般我们可以在一个项目中同时使用特性路由和传统路由两种技术。要启用特性路由只需要在RouteConfig.cs路由配置中调用方法:MapMvcAttributeRoutes()即可。
特性路由可以通过[Route]和[RoutePrefix]特性来自定义路由,[RoutePrefix]只作用于Controller,当定义了[RoutePrefix]特性时必须定义[Route]特性,此时的接口路由是“协议+IP+Port+RoutePrefix特性+Route特性”,如图:http://localhost:54639/Test/TestView
注意:当Action定义了Router特性时Controller中定义的Route特性中的action指向的是Action中的Route特性,而不是Action方法名,也就是说下图中通过http://localhost:54639/Test/index路由是访问不到资源的。
[Route]主要作用于Action路由重写,当在Action前定义了Route特性时,路由只能通过Route特性中的路由进行资源访问,如果希望当前Action支持多路由访问则可以定义多个Route特性。如下图该方法即可以通过http://localhost:54639/home/test访问,也可以通过http://localhost:54639/test访问。
? 当[Route]作用于Controller时RouteData 必须包含名为“action”且值为非空的字符串,此时Acion中就可以不用再单独定义Route特性了。如[Route("Home/{action}")],当我们请求http://localhost:54639/Home/index时系统会自动去寻找符合特性路由[Route("Home/{action}")]下的index方法。
通过前面的路由配置我们可以实现大部分路由配置了,但仔细查看还是会发现问题,作为路由参数匹配时路由参数会匹配任何非空字符,所以不管是int类型还是string类型都能匹配到当前路由。此时系统发现满足路由的Acion方法有两个,这时系统就会将参数作为方法参数传递给Action并试图执行两个Action方法,此时系统会报错:当前请求在以下操作方法之间不明确。
? 这时我们就可以通过路由约束来进行控制,当路由参数满足路由约束条件时才匹配该路由并执行相应的Acion方法,当路由参数为int类型时则执行第一条路径,否则则选择第二条路线。通过在参数约束后面添加一个问号表示URI参数是可选的,也可以添加等号为其指定默认值。 当然也可以将多个约束应用于一个参数,只要用冒号分隔开即可。
? .Net提供了大量的路由约束且默认加载了这些路由约束,当我们使用约束时会去验证路由参数,通过TryParse()方法对参数尝试转换变量并提取参数字符串,返回ture则通过,false则跳过。除了通过使用类型和值约束来约束也可以用正则表达式来约束路由,只有与正则指定的类型匹配才能通过该路由。?
更多ASP.NET MVC实战技巧可以参考专栏:ASP.NET MVC实战系列
TML 帮助器用于修改 HTML 输出。
HTML 帮助器
通过 MVC,HTML 帮助器类似于传统的 ASP.NET Web Form 控件。
就像 ASP.NET 中的 Web Form 控件,HTML 帮助器用于修改 HTML。但是 HTML 帮助器是更轻量级的。与 Web Form 控件不同,HTML 帮助器没有事件模型和视图状态。
在大多数情况下,HTML 帮助器仅仅是一个返回字符串的方法。
通过 MVC,您可以创建您自己的帮助器,或者直接使用内建的 HTML 帮助器。
标准的 HTML 帮助器
MVC 包含了大多数常用的 HTML 元素类型的标准帮助器,比如 HTML 链接和 HTML 表单元素。
HTML 链接
呈现 HTML 链接的最简单的方法是使用 HTML.ActionLink() 帮助器。
通过 MVC,Html.ActionLink() 不连接到视图。它创建一个连接到控制器操作。
Razor 语法:
@Html.ActionLink("About this Website", "About")
ASP 语法:
<%=Html.ActionLink("About this Website", "About")%>
第一个参数是链接文本,第二个参数是控制器操作的名称。
上面的 Html.ActionLink() 帮助器,输出以下的 HTML:
<a href="/Home/About">About this Website</a>
Html.ActionLink() 帮助器的一些属性:
属性 | 描述 |
---|---|
.linkText | URL 文本(标签),定位点元素的内部文本。 |
.actionName | 操作(action)的名称。 |
.routeValues | 传递给操作(action)的值,是一个包含路由参数的对象。 |
.controllerName | 控制器的名称。 |
.htmlAttributes | URL 的属性设置,是一个包含要为该元素设置的 HTML 特性的对象。 |
.protocol | URL 协议,如 "http" 或 "https"。 |
.hostname | URL 的主机名。 |
.fragment | URL 片段名称(定位点名称)。 |
注释:您可以向控制器操作传递值。例如,您可以向数据库 Edit 操作传递数据库记录的 id:
Razor 语法 C#:
@Html.ActionLink("Edit Record", "Edit", new {Id=3})
Razor 语法 VB:
@Html.ActionLink("Edit Record", "Edit", New With{.Id=3})
上面的 Html.ActionLink() 帮助器,输出以下的 HTML:
<a href="/Home/Edit/3">Edit Record</a>
HTML 表单元素
以下 HTML 帮助器可用于呈现(修改和输出)HTML 表单元素:
BeginForm()
EndForm()
TextArea()
TextBox()
CheckBox()
RadioButton()
ListBox()
DropDownList()
Hidden()
Password()
ASP.NET 语法 C#:
<%=Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()){%>
<p>
<label for="FirstName">First Name:</label>
<%=Html.TextBox("FirstName") %>
<%=Html.ValidationMessage("FirstName", "*") %>
</p>
<p>
<label for="LastName">Last Name:</label>
<%=Html.TextBox("LastName") %>
<%=Html.ValidationMessage("LastName", "*") %>
</p>
<p>
<label for="Password">Password:</label>
<%=Html.Password("Password") %>
<%=Html.ValidationMessage("Password", "*") %>
</p>
<p>
<label for="Password">Confirm Password:</label>
<%=Html.Password("ConfirmPassword") %>
<%=Html.ValidationMessage("ConfirmPassword", "*") %>
</p>
<p>
<label for="Profile">Profile:</label>
<%=Html.TextArea("Profile", new {cols=60, rows=10})%>
</p>
<p>
<%=Html.CheckBox("ReceiveNewsletter") %>
<label for="ReceiveNewsletter" style="display:inline">Receive Newsletter?</label>
</p>
<p>
<input type="submit" value="Register" />
</p>
<%}%>
介绍asp.net core路由时,我初步想了下,分几篇来说明。 路由的知识点很多,参考了官方文档提取出一些重要的知识点来说。 在ASP.NET Core中是使用路由中间件来匹配传入请求的 URL 并将它们映射到操作(action方法)。路由是在程序启动时进行传统路由或属性路由定义。 路由描述如何将 URL 路径与操作相匹配。 它还用于在响应中生成送出的 URL(用于链接)。
路由操作既支持传统路由,也支持属性路由。也可混合使用。通常传统路由用于为浏览器处理 HTML 页面的控制器。属性路由用于处理 web API 的控制器。
1.1设置路由中间件
要使用传统路由,必须在UseMVC中间件中配置实现IRouteBuilder接口,在asp.net core mvc 2.2 框架下,应用程序Startup的Configure 方法中,默认路由设置如下:
app.UseMvc(routes=> { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
在对 UseMvc调用中,MapRoute 用于创建单个路由,亦称 default 路由。 大多数 MVC 应用使用带有模板的路由。对于default路由简便的方法可以使用:
app.UseMvcWithDefaultRoute();
UseMvc 和 UseMvcWithDefaultRoute 可向中间件管道添加 RouterMiddleware 的实例。 MVC 不直接与中间件交互,而是使用路由来处理请求。 MVC 通过 MvcRouteHandler 实例连接到路由。
UseMvc 不直接定义任何路由,它向属性路由的路由集合添加占位符{controller=Home}/{action=Index}/{id?} 。通过重载 UseMvc(Action<IRouteBuilder>) 则允许用户添加自己的路由,并且还支持属性路由。
1.2 传统路由
传统路由是:具有描述性的路由方案,这样URL具有可读性。传统路由格式:{controller=Home}/{action=Index}/{id?}这样的url路径是设定了一个约定: 第一段映射到控制器名称, 第二段映射到操作名称,第二段映射到可选ID。
(1) 使用默认路由:
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
使用此默认路由时: url路径/Products/List 将映射到程序ProductsController(控制器).List(action)中。 url路径/Blog/Article/17将映射到程序BlogController(控制器).Article(action)中。
(2) 多个路由:
通过添加对 MapRoute 的多次调用,可以在 UseMvc 内添加多个路由。 这样做可以定义多个约定,或添加专用于特定操作的传统路由,比如:
app.UseMvc(routes=> { routes.MapRoute("blog", "blog/{*article}", defaults: new { controller="Blog", action="Article" }); routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); });
这里的blog路由是一个专用的传统路由,这表示blog使用传统路由系统,但专用于特定的操作,也就是对于BlogController控制器的Article操作,此专用路由将始终映射。对于多个路由的路由集合会进行排序,并按添加顺序进行处理,因此,在此示例中,将先尝试 blog 路由,再尝试 default 路由。
(3) action操作的区分
在处理url请求时,当通过路由匹配到一个控制器内两项相同的action名称时,mvc必须进行区分,以选择最佳候选项,否则会引发异常(AmbiguousActionException)。
public class ProductsController : Controller { public IActionResult Edit(int id) { ... } [HttpPost] public IActionResult Edit(int id, Product product) { ... } }
此Products控制器定义了二项操作,这两项操作均与 URL 路径的 /Products/Edit/17 匹配相同。解决方案是将要提交的action加上 Http 谓词为 POST。这样post过来时,就会选择Edit(int, Product)
1.3 属性路由
通过在控制器(Controller)或操作(Action)上放置路由可实现属性路由。 不能通过传统路由访问定义属性路由的操作,反之亦然。 控制器上的任何路由属性,都会使控制器中的所有操作使用属性路由。
属性路由使用一组属性将action直接映射到路由模板。在下面的示例中,Configure 方法使用 app.UseMvc();,不传递任何路由。 HomeController 将匹配一组 URL,这组 URL 与默认路由 {controller=Home}/{action=Index}/{id?} 匹配的 URL 类似:
当去掉default默认路由模板后,只使用app.UseMvc()时。运行程序时,页面报404错误:找不到 localhost 的网页。
app.UseMvc();
(1) 属性路由基本使用
如果定义了属性路由的操作,此时就是启动属性路由功能。Home控制器的属性路由示例如下:
public class HomeController : Controller { [Route("")] [Route("Home")] [Route("Home/Index")] public IActionResult Index() { return View(); } }
在index的action上加[Route("")]属性路由。 浏览器可以使用下面三种url来访问,也是程序启动时的默认加载页面:
http://localhost:30081/
http://localhost:30081/Home/
http://localhost:30081/Home/index
(2) 属性路由精确控制
属性路由需要更多输入来指定路由;传统的默认路由处理路由的方式则更简洁。 但是,属性路由允许(并需要)精确控制应用于每项操作的路由模板。下面示例是精确控制每项操作的路由模板,比如url访问/home/index时,即是调用MyIndex的action方法。
public class MyDemoController : Controller { [Route("")] [Route("Home")] [Route("Home/Index")] public IActionResult MyIndex() { return View("Index"); } }
1.4 使用 Http[Verb] 属性的属性路由
属性路由还可以使用 Http[Verb] 属性,比如 HttpPostAttribute。 所有这些属性都可采用路由模板。 此示例展示,同一路由模板匹配的两项操作:
[HttpGet("/products")] public IActionResult ListProducts() { // ... } [HttpPost("/products")] public IActionResult CreateProduct(...) { // ... }
当 Http 谓词为 GET 时将执行ProductsApi.ListProducts 操作, 当 Http 谓词为 POST 时将执行 ProductsApi.CreateProduct。生成 REST API 时,很少会在操作方法上使用 [Route(...)]。 建议使用更特定的 Http*Verb*Attributes 来明确 API 所支持的操作。 REST API 的客户端需要知道映射到特定逻辑操作的路径和 Http 谓词。
例如下面一个web api访问路由,使用Http*Verb*Attributes 来明确定义如下:
public class ProductsApiController : Controller { [HttpGet("/products/{id}", Name="Products_List")] public IActionResult GetProduct(int id) { ... } }
上面定义只有针对如访问url如: /products/3(而非 /products)之类的 URL才会执行 ProductsApi.GetProduct(int) 操作。
1.5 路由合并
若要使属性路由减少重复,可将控制器Controller上的路由属性与各个操作Action上的路由属性合并。 控制器上定义的所有路由模板均作为操作上路由模板的前缀。 在控制器上放置路由属性会使控制器中的所有操作都使用属性路由。
下面是一个web api的路由合并,访问Get的方法的访问路径为: http://localhost:30081/api/Products/1
[Route("api/Products")] public class ProductsApiController : Controller { // GET api/values/5 [HttpGet("{id}")] public string Get(int id) { return "value"; } }
下面是一个控制器的路由合并。访问index页面的访问路径为: http://localhost:30081/home/index
[Route("Home")] public class HomeController : Controller { [Route("")] // Combines to define the route template "Home" [Route("Index")] // Combines to define the route template "Home/Index" [Route("/")] // Doesn't combine, defines the route template "" public IActionResult Index() { //... } }
1.6 指定属性路由参数约束
[HttpGet("Home/{id:int}",Name="Pri")] public IActionResult Privacy(int id) { return View(); }
如果输入非整数类型的参数,浏览器提示:找不到与以下网址对应的网页:http://localhost:30081/home/dd
1.7 自定义路由属性
该框架中提供的所有路由属性([Route(...)]、[HttpGet(...)] 等)都可实现 IRouteTemplateProvider接口。 当应用启动时,MVC 会查找控制器类和操作方法上的属性,并使用可实现 IRouteTemplateProvider的属性生成一组初始路由。
下面使用IRouteTemplateProvider 来定义自己的路由属性。每个 IRouteTemplateProvider 都允许定义一个包含自定义路由模板、顺序和名称的路由:
public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider { //实现接口的三个属性,这里的[controller]是一个标记替换。 public string Template=> "api/[controller]/{action}/{id?}"; public int? Order { get; set; } public string Name { get; set; } } public class ProductsApiController : Controller { // GET api/values/5 // [HttpGet("{id}")] [MyApiController()] public string Get(int id) { return "value"; } }
通过访问url: http://localhost:30081/api/ProductsApi/get/1 来调用get方法。
参考文献
官方资料:asp.net core routing
欢迎添加个人微信号:Like若所思。
欢迎关注我的公众号,不仅为你推荐最新的博文,还有更多惊喜和资源在等着你!一起学习共同进步!
*请认真填写需求信息,我们会在24小时内与您取得联系。