.NET 云原生架构师训练营(模块二 基础巩固 路由与终结点)--学习笔记

简介: - 路由模板- 约定路由- 特性路由- 路由冲突- 终结点

2.3.3 Web API -- 路由与终结点

  • 路由模板
  • 约定路由
  • 特性路由
  • 路由冲突
  • 终结点

ASP.NET Core 中的路由:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/routing?view=aspnetcore-5.0

UseRouting 添加路由中间件到管道,路由中间件用来匹配 url 和具体的 endpoint,然后执行 endpoint

UseEndpoints 添加或者注册 endpoint 到程序中,使得路由中间件可以发现它们

  • MapRazorPages for Razor Pages 添加所有 Razor Pages 终结点
  • MapControllers for controllers 添加所有 controller 终结点
  • MapHub for SignalR 添加 SignalR 终结点
  • MapGrpcService for gRPC 添加 gRPC 终结点

路由模板

路由模板由 token 和其他特定字符组成。比如“/”,特定字符进行路由匹配的时候必须全部匹配

/hello/{name:alpha}

{name:alpha} 是一段 token,一段 token 包括一个参数名,可以跟着一个约束(alpha)或者一个默认值(mingson),比如 {name=mingson} ,或者直接 {name}

app.UseEndpoints(endpoints =>
{
    //endpoints.MapControllers();
    endpoints.MapGet("/hello/{name:alpha}", async context =>
    {
        var name = context.Request.RouteValues["name"];
        await context.Response.WriteAsync($"Hello {name}!");
    });
});
AI 代码解读

路由模板中的参数被存储在 HttpRequest.RouteValues 中

大小写不敏感

url 中如果有符合,在模板中用{}代替

catch-all 路由模板

  • 在 token 前用 或者 加在参数名前,比如 blog/{slug}
  • blog/ 后面的字符串会当成 slug 的路由参数值,包括 "/",比如浏览器输入 blog/my/path 会匹配成 foo/my%2Fpath,如果想要得到 blog/my/path 则使用两个 ,foo/{path}
  • 字符串.也是可选的,比如 files/{filename}.{ext?},如果要输入 /files/myFile 也能匹配到这个路由
//app.Run(async context =>
//{
//    await context.Response.WriteAsync("my middleware 2");
//});

app.UseEndpoints(endpoints =>
{
    //endpoints.MapControllers();

    // 将终结点绑定到路由上
    endpoints.MapGet("/hello", async context =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
});
AI 代码解读

启动程序,访问:https://localhost:5001/hello

输出如下:

my middleware 1Hello World!
AI 代码解读

获取路由模板参数

endpoints.MapGet("/blog/{*title}", async context =>
{
    var title = context.Request.RouteValues["title"];
    await context.Response.WriteAsync($"blog title: {title}");
});
AI 代码解读

启动程序,访问:https://localhost:5001/blog/my-title

输出如下:

my middleware 1blog title: my-title
AI 代码解读

constraint 约束

18.jpg
19.jpg

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }
AI 代码解读
app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
        context => 
        {
            return context.Response.WriteAsync("inline-constraint match");
        });
});
AI 代码解读

约定路由

默认

endpoints.MapDefaultControllerRoute();
AI 代码解读

自定义

endpoints.MapControllerRoute("default","{controller=Home}/{action=Index}/{id?}");
AI 代码解读
// 约定路由
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

// 约定路由也可以同时定义多个
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");

    endpoints.MapControllerRoute(
        name: "blog",
        pattern: "blog/{*article}",
        defaults: new {controller = "blog", action = "Article"});
});
AI 代码解读

特性路由

controller

[Route("[controller]")]
AI 代码解读

http method

[HttpGet("option")]

[HttpGet]
[Route("option")]

[HttpGet]
[Route("option/{id:int}")]
AI 代码解读

路由冲突

[HttpGet]
//[Route("option")]
public IActionResult GetOption()
{
    return Ok(_myOption);
}
AI 代码解读

如果路由相同,启动程序会报错:

AmbiguousMatchException: The request matched multiple endpoints. Matches:
HelloApi.Controllers.ConfigController.GetOption (HelloApi)
HelloApi.Controllers.ConfigController.GetConfigurations (HelloApi)
AI 代码解读

终结点

ASP.NET Core 终结点是:

  • 可执行:具有 RequestDelegate。
  • 可扩展:具有元数据集合。
  • Selectable:可选择性包含路由信息。
  • 可枚举:可通过从 DI 中检索 EndpointDataSource 来列出终结点集合。

终结点可以:

  • 通过匹配 URL 和 HTTP 方法来选择。
  • 通过运行委托来执行。

17.jpg

中间件的每一步都在匹配终结点,所以路由和终结点之间的中间件可以拿到终结点的信息

app.UseRouting();

// 路由和终结点之间的中间件可以拿到终结点的信息
app.Use(next => context =>
{
    // 获取当前已经被选择的终结点
    var endpoint = context.GetEndpoint();
    if (endpoint is null)
    {
        return Task.CompletedTask;
    }
    // 输出终结点的名称
    Console.WriteLine($"Endpoint: {endpoint.DisplayName}");
    // 打印终结点匹配的路由
    if (endpoint is RouteEndpoint routeEndpoint)
    {
        Console.WriteLine("Endpoint has route pattern: " +
                          routeEndpoint.RoutePattern.RawText);
    }
    // 打印终结点的元数据
    foreach (var metadata in endpoint.Metadata)
    {
        Console.WriteLine($"Endpoint has metadata: {metadata}");
    }

    return Task.CompletedTask;
});

app.UseEndpoints(endpoints =>
{
    //endpoints.MapControllers();

    // 将终结点绑定到路由上
    endpoints.MapGet("/blog/{title}", async context =>
    {
        var title = context.Request.RouteValues["title"];
        await context.Response.WriteAsync($"blog title: {title}");
    });
});
AI 代码解读

启动程序,访问:https://localhost:5001/blog/my-first-blog

控制台输出如下:

Endpoint: /blog/{title} HTTP: GET
Endpoint has route pattern: /blog/{title}
Endpoint has metadata: System.Runtime.CompilerServices.AsyncStateMachineAttribute
Endpoint has metadata: System.Diagnostics.DebuggerStepThroughAttribute
Endpoint has metadata: Microsoft.AspNetCore.Routing.HttpMethodMetadata
AI 代码解读

打印 http 方法

// 打印终结点的元数据
foreach (var metadata in endpoint.Metadata)
{
    Console.WriteLine($"Endpoint has metadata: {metadata}");
    // 打印 http 方法
    if (metadata is HttpMethodMetadata httpMethodMetadata)
    {
        Console.WriteLine($"Current Http Method: {httpMethodMetadata.HttpMethods.FirstOrDefault()}");
    }
}
AI 代码解读

启动程序,访问:https://localhost:5001/blog/my-first-blog

控制台输出如下:

Current Http Method: GET
AI 代码解读

修改终结点名称、元数据

app.UseEndpoints(endpoints =>
{
    //endpoints.MapControllers();

    // 将终结点绑定到路由上
    endpoints.MapGet("/blog/{title}", async context =>
        {
            var title = context.Request.RouteValues["title"];
            await context.Response.WriteAsync($"blog title: {title}");
        }).WithDisplayName("Blog")// 修改名称
        .WithMetadata("10001");// 修改元数据
});
AI 代码解读
  • 调用 UseRouting 之前,终结点始终为 null。
  • 如果找到匹配项,则 UseRouting 和 UseEndpoints 之间的终结点为非 null。
  • 如果找到匹配项,则 UseEndpoints 中间件即为终端。 稍后会在本文档中定义终端中间件。
  • 仅当找不到匹配项时才执行 UseEndpoints 后的中间件。

GitHub源码链接:

https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/HelloApi

目录
相关文章
极氪汽车云原生架构落地实践
随着极氪数字业务的飞速发展,背后的 IT 技术也在不断更新迭代。极氪极为重视客户对服务的体验,并将系统稳定性、业务功能的迭代效率、问题的快速定位和解决视为构建核心竞争力的基石。
深圳农商银行三代核心系统全面投产 以云原生架构筑牢数字化转型基石
深圳农商银行完成第三代核心系统全面上云,日均交易超3000万笔,峰值处理效率提升2倍以上。扎根深圳70余年,与阿里云共建“两地三中心”分布式云平台,实现高可用体系及全栈护航。此次云原生转型为行业提供可复制样本,未来将深化云计算与AI合作,推动普惠金融服务升级。
256 17
PolarDB开源:云原生数据库的架构革命
本文围绕开源核心价值、社区运营实践和技术演进路线展开。首先解读存算分离架构的三大突破,包括基于RDMA的分布式存储、计算节点扩展及存储池扩容机制,并强调与MySQL的高兼容性。其次分享阿里巴巴开源治理模式,涵盖技术决策、版本发布和贡献者成长体系,同时展示企业应用案例。最后展望技术路线图,如3.0版本的多写多读架构、智能调优引擎等特性,以及开发者生态建设举措,推荐使用PolarDB-Operator实现高效部署。
176 2
深入理解云原生架构及其在现代企业中的应用
随着数字化转型的浪潮席卷全球,企业正面临着前所未有的挑战与机遇。云计算技术的迅猛发展,特别是云原生架构的兴起,正在重塑企业的IT基础设施和软件开发模式。本文将深入探讨云原生的核心概念、关键技术以及如何在企业中实施云原生策略,以实现更高效的资源利用和更快的市场响应速度。通过分析云原生架构的优势和面临的挑战,我们将揭示它如何助力企业在激烈的市场竞争中保持领先地位。
172 13
探索云原生技术:容器化与微服务架构的融合之旅
本文将带领读者深入了解云原生技术的核心概念,特别是容器化和微服务架构如何相辅相成,共同构建现代软件系统。我们将通过实际代码示例,探讨如何在云平台上部署和管理微服务,以及如何使用容器编排工具来自动化这一过程。文章旨在为开发者和技术决策者提供实用的指导,帮助他们在云原生时代中更好地设计、部署和维护应用。
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
184 3
云原生时代的应用架构演进:从微服务到 Serverless 的阿里云实践
云原生技术正重塑企业数字化转型路径。阿里云作为亚太领先云服务商,提供完整云原生产品矩阵:容器服务ACK优化启动速度与镜像分发效率;MSE微服务引擎保障高可用性;ASM服务网格降低资源消耗;函数计算FC突破冷启动瓶颈;SAE重新定义PaaS边界;PolarDB数据库实现存储计算分离;DataWorks简化数据湖构建;Flink实时计算助力风控系统。这些技术已在多行业落地,推动效率提升与商业模式创新,助力企业在数字化浪潮中占据先机。
233 12
一个适用于 .NET 的开源整洁架构项目模板
一个适用于 .NET 的开源整洁架构项目模板
117 26
云原生架构的崛起:企业数字化转型的加速器
在当今快速发展的技术环境中,企业正面临着前所未有的变革压力。本文深入探讨了云原生架构如何成为推动企业数字化转型的关键力量。通过分析其核心概念、优势以及实施策略,本文旨在为读者提供对云原生技术的全面理解,展示其在现代企业中不可或缺的作用。
127 19

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问