在 ASP.NET Core 中,路由是一个非常重要的概念,它决定了如何将传入的请求映射到相应的处理程序。本文将详细介绍 ASP.NET Core 中的路由系统,包括路由的基本原理、路由模板、路由参数、路由约束等内容,并提供相应的代码示例。

基本示例

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build(); app.MapGet("/Hello", () => "Hello World!"); app.Run();

前面的示例包含使用 MapGet 方法的单个终结点:

  • 当 HTTP GET 请求发送到 URL /Hello时:

    • 将执行请求委托。
    • Hello World! 会写入 HTTP 响应。
  • 如果请求方法不是 GET 或根 URL 不是 /Hello,则无路由匹配,并返回 HTTP 404。

UseRouting 和UseEndpoints

在asp.net core5之前的默认模板项目里面,我们都能看到UseRouting和UseEndpoints这两个中间件。用于配置路由。但是在新版本使用 WebApplicationBuilder配置中间件管道时,该管道使用 UseRouting 和 UseEndpoints 包装在 Program.cs 中添加的中间件,不需要显式调用。但是也可以手动显示调用这个方法来修改中间件的执行顺序。

路由基本原理

在 ASP.NET Core 中,路由系统负责将传入的 URL 请求映射到相应的处理程序。它通过匹配传入的 URL 和预定义的路由模板来确定请求应该由哪个处理程序处理。路由系统的工作流程如下:

  1. 接收传入的 URL 请求。
  2. 根据路由模板匹配请求的 URL。
  3. 如果找到匹配的路由,则将请求转发给相应的处理程序。
  4. 如果没有找到匹配的路由,则返回 404 错误。

路由模板

路由模板是用于定义路由的模式字符串。它可以包含静态文本和占位符,用于匹配传入的 URL。占位符由花括号包围,例如 {controller}、{action} 等。路由模板中的占位符可以用于捕获 URL 中的参数,并将其传递给处理程序。以下是一个示例路由模板:

app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" }
);

如果路由找到匹配项,{} 内的令牌定义绑定的路由参数。 可在路由段中定义多个路由参数,但必须用文本值隔开这些路由参数。
在上面的示例中,{controller}、{action} 和 {id} 是占位符,/是文本值,它们将匹配传入的 URL 中相应的部分。{id?} 中的问号表示参数是可选的。例如,对于 URL /Home/Index/123,controller 的值将是 Home,action 的值将是 Index,id 的值将是 123。
我们新建一个HomeController

public class HomeController : Controller
{
[HttpGet]
public IActionResult Index(string? id)
{
return Ok(new { id });
}
}

然后启动服务请求根路径/和/Home/Index/123


可以看到,请求顺利。
需要注意的是,这种对ApiController无效,适合MVC模式。只要有ApiController特性标签,则必须使用[Route]特性标记路由。

路由参数

路由参数是从 URL 中捕获的值,它们可以用于向处理程序传递数据。在路由模板中,可以使用占位符来定义路由参数。在处理程序中,可以使用属性路由或参数路由的方式来接收路由参数。

属性路由

属性路由是通过在处理程序的属性上添加路由特性来定义的。属性路由的示例如下:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetId(int id)
{
return Ok(new { id });
}
}

在上面的示例中,[Route("api/[controller]")] 表示该控制器的路由模板是 api/[controller],其中 [controller] 是一个占位符,它将被控制器的名称替换。[HttpGet("{id}")] 表示 GetId 方法的路由模板是 {id},它将匹配传入的 URL 中的 id 参数。使用swagger测试响应:

参数路由

参数路由是通过在处理程序的方法参数上添加路由特性来定义的。参数路由的示例如下:

[HttpGet("GetId/{id}")]
public IActionResult GetIdTow(int id)
{
return Ok(new { id });
}

在上面的示例中,[HttpGet("GetId/{id}")] 表示该方法的路由模板是 GetId/{id},其中 id 是一个占位符,它将匹配传入的 URL 中的 id 参数。使用swagger测试响应:

路由约束

路由约束用于限制路由模板中参数的值。它可以是预定义的约束,也可以是自定义的约束。预定义的约束包括:

  • int:表示参数必须是整数。
  • bool:表示参数必须是布尔值。
  • datetime:表示参数必须是日期时间。
  • decimal:表示参数必须是十进制数。
  • double:表示参数必须是双精度浮点数。
  • float:表示参数必须是单精度浮点数。
  • guid:表示参数必须是 GUID。
  • long:表示参数必须是长整数。

下表是官方给出的约束表格:

要在路由模板中使用约束,可以在参数名称后面使用冒号 :,并指定约束的名称。例如,{id:int} 表示 id 参数必须是整数。
我们在GetIdTowi就上整数和最小值1的约束。

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetId(int id)
{
return Ok(new { id });
}
[HttpGet("GetId/{id:int:min(1)}")]
public IActionResult GetIdTow(int id)
{
return Ok(new { id });
}
}

然后分别尝试字符串和小于1的数字:

自定义的约束可以通过实现 IRouteConstraint 接口来创建。以下是一个官方示例自定义约束的代码,实现 NoZeroesRouteConstraint 可防止将 0 用于路由参数:

[ApiController]
[Route("api/[controller]")]
public class NoZeroesController : ControllerBase
{
[HttpGet("{id:noZeroes}")]
public IActionResult Get(string id) =>
Content(id);
}
public class NoZeroesRouteConstraint : IRouteConstraint
{
private static readonly Regex _regex = new(
@"^[1-9]*$",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromMilliseconds(100)); public bool Match(
HttpContext? httpContext, IRouter? route, string routeKey,
RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.TryGetValue(routeKey, out var routeValue))
{
return false;
} var routeValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture); if (routeValueString is null)
{
return false;
} return _regex.IsMatch(routeValueString);
}
}

若要使用自定义 IRouteConstraint,必须在服务容器中使用应用的 ConstraintMap 注册路由约束类型。 ConstraintMap 是将路由约束键映射到验证这些约束的 IRouteConstraint 实现的目录。 应用的 ConstraintMap 可作为 AddRouting 调用的一部分在 Program.cs 中进行更新,也可以通过使用 builder.Services.Configure 直接配置 RouteOptions 进行更新。

builder.Services.AddRouting(options =>
options.ConstraintMap.Add("noZeroes", typeof(NoZeroesRouteConstraint)));

尝试请求id为0时:

请求不为0时候:

ASP.NET Core 中的路由系统,包括路由的基本原理、路由模板、路由参数、路由约束和路由属性。通过灵活使用路由系统,可以实现灵活的 URL 映射和参数传递,从而构建强大的 Web 应用程序。

欢迎进群催更。

asp.net core之路由的更多相关文章

  1. ASP.NET Core的路由[5]:内联路由约束的检验

    当某个请求能够被成功路由的前提是它满足某个Route对象设置的路由规则,具体来说,当前请求的URL不仅需要满足路由模板体现的路径模式,请求还需要满足Route对象的所有约束.路由系统采用IRouteC ...

  2. ASP.NET Core的路由[4]:来认识一下实现路由的RouterMiddleware中间件

    虽然ASP.NET Core应用的路由是通过RouterMiddleware这个中间件来完成的,但是具体的路由解析功能都落在指定的Router对象上,不过我们依然有必要以代码实现的角度来介绍一下这个中 ...

  3. ASP.NET Core的路由[3]:Router的创建者——RouteBuilder

    在<注册URL模式与HttpHandler的映射关系>演示的实例中,我们总是利用一个RouteBuilder对象来为RouterMiddleware中间件创建所需的Router对象,接下来 ...

  4. ASP.NET Core的路由[2]:路由系统的核心对象——Router

    ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...

  5. ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系

    ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的.如果我们将最终处理HTTP请求的组件称为HttpHandler,那么RouterMiddleware中间 ...

  6. ASP.NET Core 入门教程 3、ASP.NET Core MVC路由入门

    一.前言 1.本文主要内容 ASP.NET Core MVC路由工作原理概述 ASP.NET Core MVC带路径参数的路由示例 ASP.NET Core MVC固定前/后缀的路由示例 ASP.NE ...

  7. 如何在ASP.NET Core中构造UrlHelper,及ASP.NET Core MVC路由讲解

    参考文章: Unable to utilize UrlHelper 除了上面参考文章中介绍的方法,其实在ASP.NET Core MVC的Filter拦截器中要使用UrlHelper非常简单.如下代码 ...

  8. ASP.NET Core 属性路由 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 属性路由 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 属性路由 经过前面章节的学习,想必你已经对 ASP.NET Core ...

  9. ASP.NET Core 入门笔记4,ASP.NET Core MVC路由入门

    敲了一部分,懒得全部敲完,直接复制大佬的博客了,如有侵权,请通知我尽快删除修改 摘抄自https://www.cnblogs.com/ken-io/p/aspnet-core-tutorial-mvc ...

  10. ASP.NET Core端点路由 作用原理

    端点路由(Endpoint Routing)最早出现在ASP.NET Core2.2,在ASP.NET Core3.0提升为一等公民. Endpoint Routing的动机 在端点路由出现之前,我们 ...

随机推荐

  1. ABC267G Increasing K Times 题解

    做这道题,很有感悟,发篇文. 先给数列从小到大排个序. 接下来设 \(f_{i,j}\) 表示前 \(i\) 个数的排列形成 \(j\) 个上坡的方案数. 接下来考虑转移,分为插入第 \(i\) 个数 ...

  2. C#处理医学影像(四):基于Stitcher算法拼接人体全景脊柱骨骼影像

    在拍摄脊柱或胸片时,经常会遇到因设备高度不够需要分段拍摄的情况, 对于影像科诊断查阅影像时希望将分段影像合并成一张影像,有助于更直观的观察病灶, 以下图为例的两个分段影像:       我们使用Ope ...

  3. AI 绘画基础 - 细数 Stable Diffusion 中的各种常用模型 【🧙 魔导士装备图鉴】

    AI 绘画新手魔导士在刚开始玩 Stable Diffusion 时总会遇到各种新的概念,让人困惑,其中就包括各种模型和他们之间的关系. 魔法师入门得先认识各种法师装备(各种模型),让我们遇到问题知道 ...

  4. 2022-11-26:给定一个字符串s,只含有0~9这些字符 你可以使用来自s中的数字,目的是拼出一个最大的回文数 使用数字的个数,不能超过s里含有的个数 比如 : 39878,能拼出的最大回文数是

    2022-11-26:给定一个字符串s,只含有0~9这些字符 你可以使用来自s中的数字,目的是拼出一个最大的回文数 使用数字的个数,不能超过s里含有的个数 比如 : 39878,能拼出的最大回文数是 ...

  5. 使用4G通信模块和MQTT协议,完成物联网设备开发。

    使用4G通信模块和MQTT协议,完成物联网设备开发. (1)安装并使用4G模块通信模块,建立microPython开发环境: (2)使用提供的Demo开发例程,使用MQTT传输协议连接阿里或腾讯网站, ...

  6. Selenium - 元素操作(1) - 基础操作/元素信息/元素检查

    Selenium - 元素操作 元素示例 基础操作 点击元素: .click() # 点击百度一下按钮 driver.find_element_by_id("su").click( ...

  7. Django4全栈进阶之路6 对各类数据库连接设置

    Django 4 支持多种类型的数据库连接,包括 MySQL.PostgreSQL.SQLite.Oracle 等.对于不同类型的数据库,需要进行不同的设置.下面是 Django 4 对各类数据库连接 ...

  8. vue请求后端数据和跨域问题

    最近遇到的一个问题 后端写好的接口,前端怎么获取数据 这是我后端的接口:GET 接口 这是我前端运行的项目地址: 简单使用: 咱门前端使用 颇受好评的 axios 来发起请求 这是它的官网:https ...

  9. 「P2」试下1个半月能不能水出个毕设

    0.目标 将上个 springboot 项目 + html 中的html用Vue来重写,也就是在原springboot项目中集成Vue 1.在界面上,将html改成vue的形式 1.1.原html & ...

  10. Prompt Engineering优化原则 - 以Webshell代码解释为例

    一.LLM prompt优化原则 本文围绕"PHP代码解释"这一任务,讨论LLM prompt优化原则. 代码样例如下: <?php echo "a5a5aa555 ...