在 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. SSM之简单的CRUD

    文章目录 前言 项目介绍 项目代码介绍 数据库文件 源码介绍 代码展示 配置文件 业务逻辑代码 总结 前言 大家好呀,前面不是说最近在学习SSM么,可能学的不是那么深,不过刚刚开始,学完肯定需要先动手 ...

  2. C++ | 类继承

    1. 概述 C++有3种继承方式:公有继承(public).保护继承(protected).私有继承(private). 一个B类继承于A类,或称从类A派生类B.这样的话,类A称为基类(父类),类B称 ...

  3. 音视频八股文(6)-- ffmpeg大体介绍和内存模型

    播放器框架 常用音视频术语 • 容器/文件(Conainer/File):即特定格式的多媒体文件, 比如mp4.flv.mkv等. • 媒体流(Stream):表示时间轴上的一段连续数据,如一 段声音 ...

  4. 2021-02-04:第一年农场有1只成熟的母牛A,往后的每年:①每一只成熟的母牛都会生一只母牛 ②每一只新出生的母牛都在出生的第三年成熟 ③每一只母牛永远不会死 。请问N年后牛的数量是多少 ?

    2021-02-04:第一年农场有1只成熟的母牛A,往后的每年:①每一只成熟的母牛都会生一只母牛 ②每一只新出生的母牛都在出生的第三年成熟 ③每一只母牛永远不会死 .请问N年后牛的数量是多少 ?福哥答 ...

  5. Django4全栈进阶之路18 项目实战(用户管理):user_edit.html用户编辑画面设计

    1.模块 {% extends 'base.html' %} {% block content %} <!-- 编辑用户表单 --> <div class="card mt ...

  6. django4 前后端分离和不分离的优缺点

    Django4可以采用前后端分离或者不分离两种方式来开发Web应用,它们各有优缺点. 前后端分离的优点: 前后端职责分离:前端负责视图展示.用户交互,后端负责数据处理.逻辑处理,分工明确,开发效率高. ...

  7. json在线效验检测工具

    json在线效验检测工具:https://www.sojson.com/ 解析结果: { 'os_type': 'Windows', 'os_release': '10 64bit 10.0.1904 ...

  8. 码云SSH公钥及仓库建设

    码云SSH公钥及仓库建设 第一步注册码云账号并按图示点击 在新打开的界面,按图示点击 进入点击如下图步骤 然后照着做下图 ssh-keygen -t rsa -C "xxxxx@xxxxx. ...

  9. Java程序设计复习提纲(下:图形界面)

    目录 上:Java程序设计复习提纲(上:入门语法) - 孤飞 - 博客园 (cnblogs.com) 基本语法与编译运行 数据类型和关键字 常用语法 数组与字符串 异常处理 中:Java程序设计复习提 ...

  10. Blazor HyBrid在香橙派(Ubuntu Arm)运行的效果

    Blazor HyBrid在香橙派(Ubuntu Arm)运行的效果 准备香橙派一块!当前教程使用的是香橙派5 4G开发板 准备.NET环境 安装.NET Core依赖 sudo apt instal ...