ASP.NET Core 的 Routing
ASP.NET Core 的 Routing
ASP.NET Core 的 controllers 使用Routing 中间件匹配客户端的 url 请求,然后映射到对应的 controller 的处理方法(Action)上。
Actions 可以是 常规路由 或 属性路由 的映射。
MVC App一般使用常规路由。
REST APIs 应该使用属性路由。
MVC App 中用的常规路由
使用 MapControllerRoute() 方法,创建一个单一路由。
app.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
这个单一路由的名字是"default"。
这个单一路由的模板是"{controller=Home}/{action=Index}/{id?}",Home是默认Controller名称,Index是默认Action名称。
这个路由模板:
- 匹配的url路径类似:/Products/Details/5
- 解析的参数值是:{ controller = Products, action = Details, id = 5 }
如果有两个Controller 的定义是这样的:
public class ProductsController : Controller
{public IActionResult Details(int id){// use id;}
}
public class HomeController : Controller
{public IActionResult Index() { ... }
}
如果有 url是:/Products/Details/5,
对应路由模板的 “{controller=Home}/{action=Index}/{id?}”,
因为可以找到Products Controller,所以匹配了ProductsController
- Products Controller 中的 Products
- Details 代表Action方法
- 5 对应入参 id 的值,? 表示 5 是可空的,如果id出现在url中但无值,则默认为0。
而以下 url:都会匹配到HomeController:
- /Home/Index/17
- /Home/Index
- /Home 可以找到Home controllers,没有指定具体的则找默认的 Index action
- / 没有具体指定controllers和action,则找默认的Home controllers 和 Index action
注意:匹配的过程只基于Controllers名称和Action名称,与代码的命名空间,文件夹层级,Action的参数无关。
设置多个常规路由
可以多次调用 app.MapControllerRoute()。
app.MapControllerRoute(name: "blog",pattern: "blog/{*article}",defaults: new { controller = "Blog", action = "Article" });
app.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
blog路由在这里是一个专用的常规路由,符合规则的 url 都会映射到BlogController的Article方法。
“/Blog”, “/Blog/Article”, 和 “/Blog/{any-string}” 都会映射到BlogController的Article方法。
blog路由优先于default路由进行匹配,因为它先被注册。
Action 冲突
如果多个Action都被路由系统匹配,那么会:
- 选择最匹配的,或
- 抛出异常
比如url /Products/Edit/17 会同时匹配下面的两个 Action
public class ProductsController : Controller
{public IActionResult Edit(int id){return ControllerContext.MyDisplayRouteInfo(id);}[HttpPost]public IActionResult Edit(int id, Product product){return ControllerContext.MyDisplayRouteInfo(id, product.name);}
}
而一般来说,只有id入参的Action,url 一般是GET方法,而入参是int id, Product product的Action,url一般是POST方法。
所以需要使用[HttpGet] 或者 [HttpPOST] 来标记Action,让路由系统匹配最佳的Action,HTTP Method属性包括:
- [HttpGet]
- [HttpPost]
- [HttpPut]
- [HttpDelete]
- [HttpHead]
- [HttpPatch]
REST APIs 中用的属性路由
属性路由没有像传统路由那样的通配路由,而且不再通过Controller和Action的名称匹配,除非使用占位符匹配。
直接在Controller的Action中用属性定义:
public class HomeController : Controller
{[Route("")][Route("Home")][Route("Home/Index")][Route("Home/Index/{id?}")][HttpGet]public IActionResult Index(int? id){return ControllerContext.MyDisplayRouteInfo(id);}[Route("Home/About")][Route("Home/About/{id?}")]public IActionResult About(int? id){return ControllerContext.MyDisplayRouteInfo(id);}
}
意思是一个Action可以匹配多个url模板。
但应该尽量精确的使用url模板,保证效率。
占位符匹配
占位符可以是 [action], [area], 和 [controller],占位符使用area,controller和action的名称进行匹配。
例如:
public class HomeController : Controller
{[Route("")][Route("Home")][Route("[controller]/[action]")]public IActionResult Index(){return ControllerContext.MyDisplayRouteInfo();}[Route("[controller]/[action]")]public IActionResult About(){return ControllerContext.MyDisplayRouteInfo();}
}
和
[Route("[controller]/[action]")]
public class HomeController : Controller
{[Route("~/")][Route("/Home")][Route("~/Home/Index")]public IActionResult Index(){return ControllerContext.MyDisplayRouteInfo();}public IActionResult About(){return ControllerContext.MyDisplayRouteInfo();}
}
组合匹配
[ApiController]
[Route("products")]
public class ProductsApiController : ControllerBase
{[HttpGet]public IActionResult ListProducts(){return ControllerContext.MyDisplayRouteInfo();}[HttpGet("{id}")]public IActionResult GetProduct(int id){return ControllerContext.MyDisplayRouteInfo(id);}
}
在Controller上定义了[Route(“products”)],在Action 上定义了HttpMethod,那么在匹配时,会组合起来匹配,比如:
- /products 会匹配 ProductsApi.ListProducts
- /products/5 会匹配 ProductsApi.GetProduct(int)
但是 “/” 或者 “~/” 开头的模板不会被controller的模板组合。
匹配顺序
- 模板规则越具体的越优先匹配
- 根据 Order 属性,比如 [Route(“Home”, Order = 2)] 晚于 [Route(“Home”, Order = 1)]
指定参数类型
可以在Url模板中指定参数id的值类型:
public class Products14Controller : Controller
{[HttpPost("product14/{id:int}")]public IActionResult ShowProduct(int id){return ControllerContext.MyDisplayRouteInfo(id);}
}
还可以定义默认值:
public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider
{public string Template => "api/[controller]";public int? Order => 2;public string Name { get; set; } = string.Empty;
}[MyApiController]
[ApiController]
public class MyTestApiController : ControllerBase
{// GET /api/MyTestApi[HttpGet]public IActionResult Get(){return ControllerContext.MyDisplayRouteInfo();}
}
混合使用传统路由和属性路由
Actions 可以是传统路由或者属性路由,但是定义了属性路由的Actions 就不能再被传统路由匹配了,意思是属性路由的优先级更高。
而如果Controller上定义了属性路由,那么所有内部的Actions 就都不能再被传统路由匹配了。
系统保留的路由关键字
保留的路由关键字不应该用在路由匹配系统中,包括:
- action
- area
- controller
- handler
- page
而且在ulr中不可以包含ASCII的"/" 或者" ",路由系统不支持URL 转义。
URL Generation 和 环境值
ASP.NET Core App 可以生成指向Action的 URL,这个功能叫 URL Generation。
URL Generation 可以减少 hard code的URL,使代码更健壮,更好维护。
可以在controllers和views使用Url属性使用 IUrlHelper 接口的方法。
先看传统路由的例子:
public class UrlGenerationController : Controller
{public IActionResult Source(){// 生成了url: /UrlGeneration/Destinationvar url = Url.Action("Destination");return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");}public IActionResult Destination(){return ControllerContext.MyDisplayRouteInfo();}
}
这里使用的是传统路由,url 变量的值是URL的路径字符串 “/UrlGeneration/Destination”。通过组合http request的路由值(环境值):
- 环境值: { controller = “UrlGeneration”, action = “Source” }
- 环境值传给 Url.Action: { controller = “UrlGeneration”, action = “Destination” }
- 路由模板: {controller}/{action}/{id?}
- 结果: /UrlGeneration/Destination
路由模板中的每个路由参数会被环境值替代。没有值的路由参数要么使用默认值,要么跳过(可空)。
再看属性路由的例子:
public class UrlGenerationAttrController : Controller
{[HttpGet("custom")]public IActionResult Source(){var url = Url.Action("Destination");return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");}[HttpGet("custom/url/to/destination")]public IActionResult Destination(){return ControllerContext.MyDisplayRouteInfo();}
}
Source action 生成了 custom/url/to/destination。
通过Action名称生成URL
Url.Action, LinkGenerator.GetPathByAction 都用于通过Controller和Action的名称生成URL。
使用 Url.Action 时,controller 和 action的路由值由.NET 运行时生成。
假设有一个路由是这样: {a}/{b}/{c}/{d},环境值是 { a = Alice, b = Bob, c = Carol, d = David },那么路由有足够信息生成URL,不需要额外的值。
如果添加了{ d = Donovan },那么{ d = David }会被忽略,会生成URL Alice/Bob/Carol/Donovan。
如果添加了 { c = Cheryl },那么{ c = Carol, d = David } 都会被忽略。
任何不匹配路由参数的额外的值都会被放进query字符串中。比如:
public IActionResult Index()
{var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });return Content(url!);
}
会生成URL: /Products/Buy/17?color=red
下面的代码生成一个绝对路径URL:
public IActionResult Index2()
{var url = Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme);// Returns https://localhost:5001/Products/Buy/17return Content(url!);
}
通过路由名称生成URL
Url.RouteUrl 可以指定一个路由名称生成URL,而一般不指定Controller或者Action名称。
比如:
public class UrlGeneration2Controller : Controller
{[HttpGet("")]public IActionResult Source(){var url = Url.RouteUrl("Destination_Route");return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");}[HttpGet("custom/url/to/destination2", Name = "Destination_Route")]public IActionResult Destination(){return ControllerContext.MyDisplayRouteInfo();}
下面的代码生成一个指向Destination_Route的链接:
<h1>Test Links</h1>
<ul><li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>
在Action Results中生成URL
在Controlle中最常见的用法是在Action Results中返回一个URL,另一个用法是Redirect到另一个Action。
Controller基类提供了方便的方法来实现Redirect。
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Customer customer)
{if (ModelState.IsValid){// Update DB with new details.ViewData["Message"] = $"Successful edit of customer {id}";return RedirectToAction("Index");}return View(customer);
}
Area 路由
Area路由是MVC中的功能,可以把相关的功能做成一个分组。
可以通过Routing 命名空间分组controller 和 actions,也可以通过文件夹分组Views。
Areas 可以让多个controller 在不同的Area下有相同的名字。
比如:
app.MapAreaControllerRoute("blog_route", "Blog","Manage/{controller}/{action}/{id?}");
app.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
app.Run();
MapAreaControllerRoute创建的路由中,blog_route是路由名,Blog是Area名。
当匹配URL路径比如 /Manage/Users/AddUser 时,“blog_route” 路由生成的路由值是:{ area = Blog, controller = Users, action = AddUser }。
上面这个路由会匹配这个Action:
[Area("Blog")]public class UsersController : Controller{// GET /manage/users/adduserpublic IActionResult AddUser(){var area = ControllerContext.ActionDescriptor.RouteValues["area"];var actionName = ControllerContext.ActionDescriptor.ActionName;var controllerName = ControllerContext.ActionDescriptor.ControllerName;return Content($"area name:{area}" +$" controller:{controllerName} action name: {actionName}");} }
注意:没有Area属性的Controller不会匹配任何带Area的路由模板。
相关文章:

ASP.NET Core 的 Routing
ASP.NET Core 的 Routing ASP.NET Core 的 controllers 使用Routing 中间件匹配客户端的 url 请求,然后映射到对应的 controller 的处理方法(Action)上。 Actions 可以是 常规路由 或 属性路由 的映射。 MVC App一般使用常规路由。 REST API…...

IBM Spectrum LSF Explorer 为要求苛刻的分布式和任务关键型高性能技术计算环境提供强大的工作负载管理
IBM Spectrum LSF Explorer 适用于 IBM Spectrum LSF 集群的强大、轻量级报告解决方案 亮点 ● 允许不同的业务和技术用户使用单一解决方案快速创建和查看报表和仪表板 ● 利用可扩展的库提供预构建的报告 ● 自定义并生成性能、工作负载和资源使用情况的报…...

RHCE——十一、NFS服务器
NFS服务器 一、简介1、NFS背景介绍2、生产应用场景 二、NFS工作原理1、示例图2、流程 三、NFS的使用1、安装2、配置文件3、主配置文件分析3.1 实验1 4、NFS账户映射4.1 实验24.2 实验3 四、autofs自动挂载服务1、产生原因2、安装3、配置文件分析4、实验45、实验5 一、简介 1、…...

Python编程练习与解答 练习100:随机密码
编写一个生成最忌密码的函数,密码的长度应该在7-10个字符之间。每个字符应该从ASCII表的第33位到126位中随机选择。函数不接受任何参数,返回随机生成的密码作为位移结果。在文件的main程序中显示随机生成的密码。main程序只在解答没有被导入另一个文件时…...

华为云云服务器评测 | 从零开始:云耀云服务器L实例的全面使用解析指南
文章目录 一、前言二、云耀云服务器L实例要点介绍2.1 什么是云耀云服务器L实例2.1.1 浅析云耀云服务器L实例 2.2 云耀云服务器L实例的产品定位2.3 云耀云服务器L实例优势2.4 云耀云服务器L实例支持的镜像与应用场景2.5 云耀云服务器L实例与弹性云服务器(ECS…...

欧科云链研究院探析Facebook稳定币发行经历会不会在PayPal重演
引言 作者最近的报告-探析PayPal发行稳定币是否会重蹈Facebook覆辙-近期被英国的金融时报(中文版)刊登。由于该报告在欧科云链研究院内部反响较好,下面就带大家简单的剖析这篇报告的主要内容。 *这篇文章主要由对比分析(已删减&a…...

docker 容器pip、git安装异常;容器内web对外端口ping不通
1、docker 容器pip、git安装异常 错误信息: git clone https://github.com/vllm-project/vllm.git Cloning into ‘vllm’… fatal: unable to access ‘https://github.com/vllm-project/vllm.git/’: Failed to connect to 127.0.0.1 port 10808: Connection ref…...

SpringBoot Mybatis 多数据源 MySQL+Oracle+Redis
一、背景 在SpringBoot Mybatis 项目中,需要连接 多个数据源,连接多个数据库,需要连接一个MySQL数据库和一个Oracle数据库和一个Redis 二、依赖 pom.xml <dependencies><dependency><groupId>org.springframework.boot&l…...

【JavaScript 16】对象继承 原型对象属性 原型链 构造函数属性 instanceof运算符 继承 多重继承 模块
对象继承 原型对象概述instanceof运算符构造函数的继承多重继承模块 A 对象通过继承 B 对象,就能 直接拥有 B 对象的所有属性和方法(利于代码复用) 大部分面向对象的编程语言都是通过类(class)实现对象的继承 但 传统…...

地下管线三维自动建模软件MagicPipe3D V3.0发布
2023年9月1日经纬管网建模系统MagicPipe3D V3.0正式发布,该版本经过众多用户应用和反馈,在三维地下管线建模效果、效率、适配性等方面均有显著提升!MagicPipe3D本地离线参数化构建地下管网模型(包括管道、接头、附属设施等&#x…...

百度等8家企业首批上线大模型服务;大语言模型微调之道
🦉 AI新闻 🚀 百度等8家企业首批上线大模型服务 摘要:百度、字节、中科院旗下8家企业/机构的大模型通过备案,正式面向公众提供服务。百度旗下AI大模型产品文心一言率先开放,用户可下载App或登录官网体验。百川智能也…...

二、Mycat2 相关概念及读写分离
第三章 Mycat2 相关概念 3.1 概念描述 1、分库分表 按照一定规则把数据库中的表拆分为多个带有数据库实例,物理库,物理表访问路 径的分表。 解读:分库:一个电商项目,分为用户库、订单库等等。 分表:一张订单表数据数百万ÿ…...

react利用wangEditor写评论和@功能
先引入wangeditor写评论功能 import React, { useEffect, useState, useRef, forwardRef, useImperativeHandle } from react; import wangeditor/editor/dist/css/style.css; import { Editor, Toolbar } from wangeditor/editor-for-react; import { Button, Card, Col, For…...

Android之布局转圆角
Android之布局转圆角 文章目录 Android之布局转圆角说明一、效果图二、实现步骤1.自定义RoundRelativeLayout2.使用 总结 说明 很多需求比较无语,需要某个布局转圆角,像个显眼包一样,所以为了满足显眼包,必须整呐提示:…...

Linux的目录结构特点
Linux的目录结构特点 1、使用树形目录结构来组织和管理文件。 2、整个系统只有一个根目录(树根),Linux的根目录用“/”表示。 3、其他所有分区以及外部设备(如硬盘,光驱等)都是以根目录为起点࿰…...

【算法与数据结构】654、LeetCode最大二叉树
文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析:【算法与数据结构】106、LeetCode从中序与后序遍历序列构造二叉树这两道题有些类似,相关代…...

您必须尝试的 4 种经典特征提取技术!
一、说明 特征提取如何实现?其手段并不是很多,有四个基本方法,作为AI工程师不能不知。因此,本篇将对四种特征提取给出系统的方法。 二、概述 图像分类长期以来一直是计算机视觉领域的热门话题,并希望能够保持这种状态。…...

Unity中Shader的遮罩的实现
文章目录 前言一、遮罩效果的实现主要是使用对应的纹理实现的,在属性中暴露对应的遮罩纹理,对其进行采样后,最后相乘输出即可二、如果需要像和主要纹理一样流动,则需要使用和_Time篇一样的方法实现流动即可 前言 Unity中Shader的…...

架构师成长之路|Redis key过期清除策略
Eviction policies maxmemory 100mb 当我们设置的内存达到指定的内存量时,清除策略的配置方式决定了默认行为。Redis可以为可能导致使用更多内存的命令返回错误,也可以在每次添加新数据时清除一些旧数据以返回到指定的限制。 当达到最大内存限制时,Redis所遵循的确切行为是…...

ubuntu20.04使用privoxy进行http代理转http代理,并定制http代理头(hide-user-agent的使用方法)
#sudo apt-get update;sudo apt install -y privoxy #sudo apt remove privoxyprivoxy --version; rootfv-az1239-825:/tmp# privoxy --version Privoxy version 3.0.28 (https://www.privoxy.org/) rootfv-az1239-825:/tmp# 安装完毕后,先停止服务,修改配置文件,再启动服…...

任意文件读取
文章目录 渗透测试漏洞原理任意文件读取1. 任意文件读取概述1.1 漏洞成因1.2 漏洞危害1.3 漏洞分类1.4 任意文件读取1.4.1 文件读取1.4.2 任意文件读取1.4.3 权限问题 1.5 任意文件下载1.5.1 一般情况1.5.2 PHP实现1.5.3 任意文件下载 2. 任意文件读取攻防2.1 路径过滤2.1.1 过…...

微信小程序餐饮外卖系统设计与实现
摘 要 随着现在的“互联网”的不断发展。现在传统的餐饮业也朝着网络化的方向不断的发展。现在线上线下的方式来实现餐饮的获客渠道增加,可以更好地帮助餐饮企业实现更多、更广的获客需求,实现更好的餐饮销售。截止到2021年末,我国的外卖市场…...

一文速览嵌入式六大出口
嵌入式行业的前景确实十分广阔,并且在许多领域都发挥着重要作用。以下是一些关键点,说明嵌入式系统的发展潜力和前途: 1. 物联网(IoT):嵌入式系统是实现智能家居、智能城市、智能工厂等物联网设备的核心。物…...

华为云云服务器评测 | 宝塔8.0镜像应用
目录 🍒写在前面 🍒产品优势 🍒购买服务器 🍒服务器配置 🍒登录宝塔页面 🦐博客主页:大虾好吃吗的博客 🦐专栏地址:闲谈专栏地址 写在前面 云耀云服务器L实例是新一代开箱…...

构建简单的Node.js HTTP服务器,发布公网远程访问的快速方法
文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation࿰…...

ModaHub魔搭社区:向量数据库产业的现状与技术挑战
I. 向量数据库的崛起 什么是向量数据库 在过去的一段时间里,向量数据库逐渐在数据库领域崭露头角。那么,什么是向量数据库呢?简单来说,向量数据库是一种专门设计用来处理向量数据的数据库。这些向量数据可以是物理测量、机器学习模型输出、地理空间数据等。向量数据库使用…...

pmp和软件高项哪个含金量高?
人们常将PMP和高项放在一起比较,因为这两种证书都适用于项目经理职位,它们有高达60%的知识点重合度。在决定考哪一种证书之前,人们常常会感到困惑。 下面看一下pmp和软考高项的差异。 发证机构不同 PMP(Project Management Professional)是…...

手把手教你用Vite构建第一个Vue3项目
写在前面 在之前的文章中写过“如何创建第一个vue项目”,但那篇文章写的是创建vue2的 项目。 传送门如何创建第一个vue项目 打开Vue.js官网:https://cn.vuejs.org/,我们会发现Vue 2 将于 2023 年 12 月 31 日停止维护 虽然Vue2的项目还不少࿰…...

美创科技获通信网络安全服务能力评定(应急响应一级)认证!
近日,中国通信企业协会公布通信网络安全服务能力评定2023年第一批获证企业名单。 美创科技获得应急响应一级资质,成为2023年第一批获证企业之一! 通信网络安全服务能力评定是对通信网络安全服务单位从事通信网络安全服务综合能力的评定&#…...

计算机视觉与人工智能在医美人脸皮肤诊断方面的应用
一、人脸皮肤诊断方法 近年来,随着计算机技术和人工智能的不断发展,中医领域开始逐渐探索利用这些先进技术来辅助面诊和诊断。在皮肤望诊方面,也出现了一些现代研究,尝试通过图像分析技术和人工智能算法来客观化地获取皮肤相关的…...