金士顿头像
关注

ASP.NET Core Minimal API 底层原理:一个 HTTP 请求到底经历了什么?

ASP.NET Core Minimal API 底层原理:一个 HTTP 请求到底经历了什么?

前言

上一篇介绍了为什么我会在 STM32MP257 + Linux ARM64 设备上使用 ASP.NET Core,并采用:

ASP.NET Core Minimal API
        +
Static HTML/CSS/JavaScript
        +
BackgroundService
        +
Native AOT
        +
systemd

作为整个设备 Web 配置服务的基础架构。

这一篇不再停留在:

app.MapGet("/api/status", () => "OK");

这种使用层面。

我们真正要回答的是:

当浏览器请求 /api/status 时,ASP.NET Core 内部到底发生了什么?

例如下面这段代码:

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/api/status", () =>
{
    return Results.Ok(new
    {
        status = "Connected"
    });
});

app.Run();

看起来只有几行代码。

但实际上一个 HTTP 请求背后会经过:

TCP
 ↓
Kestrel
 ↓
HTTP Parser
 ↓
HttpContext
 ↓
Middleware Pipeline
 ↓
Routing
 ↓
Endpoint
 ↓
RequestDelegate
 ↓
Dependency Injection
 ↓
业务 Service
 ↓
Response Serialization
 ↓
HTTP Response

这一篇就把这个过程完整拆开。


一、先看整体架构

先建立一个整体概念。

ASP.NET Core 应用可以粗略理解为:

                Client
                  │
                  │ HTTP
                  ▼
            ┌─────────────┐
            │   Kestrel   │
            └──────┬──────┘
                   │
                   ▼
            HttpContext
                   │
                   ▼
          Middleware Pipeline
                   │
                   ▼
               Routing
                   │
                   ▼
               Endpoint
                   │
                   ▼
            RequestDelegate
                   │
                   ▼
          Application Service
                   │
                   ▼
              Response

对于我们设备端项目,则可能是:

Browser
   │
   ▼
Kestrel
   │
   ▼
Minimal API
   │
   ▼
FiveGStatusService
   │
   ▼
Runtime Snapshot
   │
   ▼
JSON
   │
   ▼
Browser

这里非常关键的一点是:

ASP.NET Core 本质上不是“Controller 框架”。

Controller、Minimal API、Razor Pages 都只是建立在 ASP.NET Core HTTP Pipeline 上面的不同编程模型。

真正核心的是:

Host
+
Server
+
Middleware
+
Routing
+
Endpoint
+
Dependency Injection

二、WebApplication.CreateBuilder 到底干了什么

我们通常从下面一行开始:

var builder = WebApplication.CreateBuilder(args);

表面看起来只是创建了一个 builder。

实际上,它会初始化 ASP.NET Core 应用运行所需要的一整套基础设施。

可以粗略理解为:

WebApplication.CreateBuilder
        │
        ├── Configuration
        │
        ├── Logging
        │
        ├── Dependency Injection
        │
        ├── Host
        │
        ├── Environment
        │
        └── Web Server

也就是说,它不是单纯创建一个 Web 对象。

它是在搭建整个应用的运行环境。


三、Generic Host 是什么

ASP.NET Core 应用底层依赖的是 .NET Generic Host。

Host 可以理解成:

应用程序的宿主。

它负责管理整个程序的生命周期。

例如:

Application Start
      │
      ▼
Service initialization
      │
      ▼
Web Server Start
      │
      ▼
BackgroundService Start
      │
      ▼
Application Running
      │
      ▼
Shutdown Signal
      │
      ▼
Service Stop
      │
      ▼
Application Exit

所以 ASP.NET Core 并不只是:

HTTP Server

实际上更准确地说是:

Application Host

这也是为什么它特别适合设备端程序。

因为我们的设备程序不仅有 HTTP:

HTTP API
5G Service
Network Monitor
Configuration Service
Firmware Service
Background Worker

这些都可以挂在同一个 Host 里面。

例如:

builder.Services.AddHostedService<FiveGService>();
builder.Services.AddHostedService<NetworkMonitorService>();

启动 ASP.NET Core 时,这些后台服务也会一起启动。


四、builder.Services 是什么

我们经常会看到:

builder.Services.AddSingleton<DeviceStatusService>();

这里的:

builder.Services

实际上是:

IServiceCollection

它是 ASP.NET Core 依赖注入容器的注册表。

例如:

builder.Services.AddSingleton<DeviceStatusService>();

可以理解为注册了一条规则:

当有人需要 DeviceStatusService
        ↓
给他同一个 DeviceStatusService 实例

最终这些注册会在:

builder.Build();

时构建成:

IServiceProvider

也就是实际的依赖注入容器。


五、ASP.NET Core 的三种 Service 生命周期

ASP.NET Core 默认提供三种最常见生命周期。

Singleton

builder.Services.AddSingleton<MyService>();

整个应用生命周期只有一个实例:

Application
   │
   └── MyService #1

所有请求共享:

Request 1 ─┐
Request 2 ─┼── MyService #1
Request 3 ─┘

设备状态 Service 很多时候适合 Singleton。

例如:

FiveGRuntimeService
DeviceConfigurationService
NetworkStateService

因为它们维护的是:

设备全局状态。


Scoped

builder.Services.AddScoped<MyService>();

通常每个 HTTP Request 一个实例:

Request 1
    └── MyService #1

Request 2
    └── MyService #2

在 Web 后台、数据库应用中非常常见。

例如:

DbContext

经常采用 Scoped。


Transient

builder.Services.AddTransient<MyService>();

每次请求依赖时创建新实例:

Resolve
 ↓
new MyService()

Resolve
 ↓
new MyService()

适合:

轻量
无状态
短生命周期

对象。


六、builder.Build() 做了什么

接下来:

var app = builder.Build();

这一步非常重要。

之前:

builder

主要还处于“配置阶段”。

例如:

注册 Service
注册 Logging
读取 Configuration
设置 Host

调用 Build 后:

ServiceCollection
      │
      ▼
ServiceProvider

Configuration
      │
      ▼
Host

Web Server Configuration
      │
      ▼
Application

最终得到:

WebApplication

可以粗略理解为:

WebApplication
=
Host
+
ServiceProvider
+
Middleware Pipeline Builder
+
Endpoint Routing

七、app.MapGet 到底做了什么

我们来看:

app.MapGet("/api/status", () =>
{
    return Results.Ok("Connected");
});

很多人会以为这里已经启动了 HTTP 请求处理。

其实没有。

这一步本质上是在:

注册 Endpoint。

也就是告诉 ASP.NET Core:

如果:

HTTP Method = GET
Path = /api/status

那么:

执行这个 Handler

可以理解为建立了一张表:

MethodPathHandler
GET/api/statusStatus Handler
GET/api/networkNetwork Handler
POST/api/configConfig Handler

Routing 后续就会根据请求匹配这里的 Endpoint。


八、什么是 Endpoint

Endpoint 是 ASP.NET Core 非常核心的概念。

一个 Endpoint 可以理解为:

一个可以处理请求的最终执行单元。

它通常包含:

Route Pattern
HTTP Method
Metadata
RequestDelegate

例如:

app.MapGet("/api/status", GetStatus);

内部概念大致是:

Endpoint
├── Route: /api/status
├── Method: GET
├── Metadata
└── RequestDelegate

最终 Routing 会找到它,然后执行。


九、RequestDelegate 是什么

ASP.NET Core HTTP Pipeline 的核心委托是:

RequestDelegate

其概念定义类似:

delegate Task RequestDelegate(HttpContext context);

也就是说,ASP.NET Core 最终把 HTTP 请求抽象成:

HttpContext
       │
       ▼
RequestDelegate
       │
       ▼
Task

所以从最底层来看:

ASP.NET Core 就是在不断调用一系列处理 HttpContext 的 delegate。


十、HttpContext 是什么

这是 ASP.NET Core 请求处理中最重要的对象之一。

每一个 HTTP Request 都会创建一个:

HttpContext

里面包含:

HttpContext
│
├── Request
│
├── Response
│
├── User
│
├── Items
│
├── Connection
│
├── RequestServices
└── Features

例如:

app.MapGet("/debug", (HttpContext context) =>
{
    return new
    {
        method = context.Request.Method,
        path = context.Request.Path,
        host = context.Request.Host.ToString()
    };
});

如果请求:

GET /debug HTTP/1.1
Host: 192.168.0.10:8080

那么:

HttpContext.Request.Method
=
GET
HttpContext.Request.Path
=
/debug

十一、Kestrel 到底是什么

ASP.NET Core 默认使用:

Kestrel

作为 Web Server。

Kestrel 真正负责的是:

监听 Socket
建立 TCP Connection
解析 HTTP
创建 Request
发送 Response

所以:

Browser

并不是直接访问 Minimal API。

中间首先经过:

Browser
   │
   │ TCP
   ▼
Kestrel

Kestrel 收到数据以后:

GET /api/status HTTP/1.1
Host: 192.168.0.10:8080
Accept: application/json

它需要解析:

Method = GET
Path = /api/status
Headers
Body
Protocol

然后 ASP.NET Core 才能继续处理。


十二、Kestrel 和 ASP.NET Core 是什么关系

这两个概念容易混淆。

简单来说:

ASP.NET Core
=
Web Framework

而:

Kestrel
=
Web Server

关系大概是:

TCP
 ↓
Kestrel
 ↓
ASP.NET Core Pipeline
 ↓
Application

类似于传统架构里的:

nginx
 ↓
Application

只不过 Kestrel 已经内置在 ASP.NET Core 运行体系中。

因此对于我们的嵌入式设备:

Browser
 ↓
Kestrel
 ↓
ASP.NET Core

很多时候不需要额外部署 nginx。


十三、app.Run() 才真正启动应用

最后:

app.Run();

这里才真正进入:

Application Running

阶段。

主要过程可以理解为:

Host Start
   │
   ├── Start Kestrel
   │
   ├── Start IHostedService
   │
   ├── Start BackgroundService
   │
   └── Listen for shutdown

例如我们设置:

ASPNETCORE_URLS=http://0.0.0.0:8080

那么 Kestrel 就开始监听:

0.0.0.0:8080

十四、一个 HTTP 请求正式开始

假设浏览器请求:

GET /api/status

第一步:

Browser
   │
   ▼
TCP Connection

例如:

192.168.0.100:53024
        ↓
192.168.0.10:8080

Kestrel Accept 这个 TCP Connection。

然后读取 HTTP 数据。


十五、Kestrel 解析 HTTP Request

浏览器发送:

GET /api/status HTTP/1.1
Host: 192.168.0.10:8080
Accept: application/json
Connection: keep-alive

Kestrel 解析以后得到:

Method
=
GET

Path
=
/api/status

Protocol
=
HTTP/1.1

然后创建请求相关数据结构。

最终 ASP.NET Core 得到一个:

HttpContext

十六、请求进入 Middleware Pipeline

接下来请求进入:

Middleware Pipeline

Middleware 是 ASP.NET Core 最重要的架构之一。

例如:

app.UseMiddleware<A>();
app.UseMiddleware<B>();
app.UseMiddleware<C>();

请求路径:

Request
   │
   ▼
Middleware A
   │
   ▼
Middleware B
   │
   ▼
Middleware C
   │
   ▼
Endpoint

Response 返回:

Endpoint
   │
   ▼
Middleware C
   │
   ▼
Middleware B
   │
   ▼
Middleware A
   │
   ▼
Client

所以 Middleware 是一个典型的:

Chain of Responsibility

也就是责任链模式。


十七、Middleware 的核心结构

一个 Middleware 的概念代码大概如下:

public async Task InvokeAsync(
    HttpContext context,
    RequestDelegate next)
{
    // 请求之前

    await next(context);

    // 响应之后
}

这里的:

next

代表下一个 Middleware。

因此:

await next(context);

实际上就是:

把请求继续向 Pipeline 后面传递。


十八、Middleware 为什么可以处理请求前后两个阶段

例如:

app.Use(async (context, next) =>
{
    Console.WriteLine("Before");

    await next();

    Console.WriteLine("After");
});

执行过程:

Before
 ↓
下一个 Middleware
 ↓
Endpoint
 ↓
下一个 Middleware 返回
 ↓
After

这其实类似:

进入调用栈
    ↓
执行 Endpoint
    ↓
退出调用栈

所以 Middleware 很适合:

Logging
Authentication
Authorization
Exception Handling
CORS
Request Timing
Security Headers

十九、Routing 在什么时候发生

假设:

GET /api/status

进入 Pipeline。

Routing 会检查所有注册过的 Endpoint:

GET /api/status
GET /api/network
POST /api/config

然后匹配:

Method = GET
Path = /api/status

最终选择:

Status Endpoint

可以理解为:

HttpRequest
     │
     ▼
Endpoint Routing
     │
     ├── /api/status
     ├── /api/network
     ├── /api/config
     └── ...

二十、Minimal API 参数是怎么自动注入的

来看:

app.MapGet(
    "/api/status",
    (DeviceStatusService service) =>
    {
        return service.GetStatus();
    });

这里我们没有手动写:

app.Services.GetRequiredService<DeviceStatusService>();

但 ASP.NET Core 自动把 Service 注入了进来。

为什么?

因为 Minimal API 在构建 Endpoint 时,会分析 Handler 参数。

例如:

(DeviceStatusService service)

发现:

DeviceStatusService

可以从 Dependency Injection Container 获取。

于是请求执行时:

HttpContext
   │
   ▼
RequestServices
   │
   ▼
IServiceProvider
   │
   ▼
DeviceStatusService

最终调用:

service.GetStatus();

二十一、Minimal API 参数绑定

Minimal API 还能自动绑定很多不同来源。

例如:

app.MapGet(
    "/api/users/{id}",
    (int id) =>
    {
        ...
    });

请求:

/api/users/10

ASP.NET Core 自动得到:

id = 10

数据来源可以包括:

Route
Query String
Header
Body
Form
Dependency Injection

例如:

app.MapGet(
    "/api/device",
    (
        string name,
        DeviceService service
    ) =>
    {
        ...
    });

请求:

/api/device?name=PLC

那么:

name

来自 Query String。

而:

service

来自 DI Container。


二十二、Endpoint Handler 真正执行

Routing 找到 Endpoint 后:

Endpoint
 ↓
RequestDelegate
 ↓
Handler

例如:

() =>
{
    return Results.Ok(
        new
        {
            status = "Connected"
        });
}

最终返回:

IResult

二十三、Results.Ok 做了什么

代码:

Results.Ok(data)

并不是立即发送 HTTP Response。

它实际上返回一个:

IResult

可以理解为:

Ok Result
│
├── StatusCode = 200
└── Value = data

后面 ASP.NET Core 再执行这个 Result。

最终形成:

HTTP/1.1 200 OK
Content-Type: application/json

以及 JSON Body。


二十四、对象是怎么变成 JSON 的

例如:

return Results.Ok(new
{
    status = "Connected"
});

这里返回的是:

C# Object

ASP.NET Core 最后需要转换成:

{
  "status": "Connected"
}

一般使用:

System.Text.Json

所以完整过程实际上是:

C# Object
   │
   ▼
System.Text.Json
   │
   ▼
UTF-8 JSON
   │
   ▼
Response Body

对于 Native AOT 项目,这一步尤其重要。

因为:

JSON Serialization 经常涉及运行时类型信息。

因此在 Native AOT 环境下,通常会进一步使用:

JsonSerializerContext
+
Source Generator

后面我们会专门写一篇。


二十五、Response 最终怎么发送回浏览器

最终 ASP.NET Core 得到:

StatusCode
Headers
Body

例如:

HTTP/1.1 200 OK
Content-Type: application/json

{"status":"Connected"}

然后交给 Kestrel。

Kestrel:

HTTP Response
     │
     ▼
TCP
     │
     ▼
Browser

浏览器 JavaScript:

const response = await fetch("/api/status");
const data = await response.json();

最终得到:

{
    status: "Connected"
}

二十六、完整请求链

现在把整个过程串起来。

浏览器:

GET /api/status

首先:

Browser

建立 TCP Connection:

Browser
   │
   ▼
Kestrel

Kestrel:

Parse HTTP

然后创建:

HttpContext

进入:

Middleware Pipeline

之后:

Routing

找到:

/api/status Endpoint

然后:

Dependency Injection

解析:

DeviceStatusService

执行:

Endpoint Handler

返回:

Results.Ok(...)

然后:

System.Text.Json

序列化。

最后:

Kestrel

发送 HTTP Response。

完整图:

Browser
   │
   │ GET /api/status
   ▼
TCP
   │
   ▼
Kestrel
   │
   ▼
HTTP Parser
   │
   ▼
HttpContext
   │
   ▼
Middleware
   │
   ▼
Routing
   │
   ▼
Endpoint
   │
   ▼
Parameter Binding
   │
   ├──── DI
   │
   ▼
Handler
   │
   ▼
Service
   │
   ▼
IResult
   │
   ▼
JSON Serialization
   │
   ▼
HttpResponse
   │
   ▼
Kestrel
   │
   ▼
TCP
   │
   ▼
Browser

二十七、放到我们的设备项目里看

在 STM32MP257 项目中,例如浏览器调用:

GET /api/fiveg/status

设计上不应该变成:

HTTP Request
   │
   ▼
发送 AT+C5GREG?
   │
   ▼
等待 Modem
   │
   ▼
返回 HTTP

因为这样 HTTP Request 和硬件操作被强耦合了。

问题很多:

串口慢
AT Timeout
Modem Reset
设备掉线
并发 Request
HTTP Timeout

二十八、更合理的设备端架构

应该采用:

BackgroundService
      │
      ▼
5G Runtime
      │
      ▼
AT Channel
      │
      ▼
Modem

后台持续维护:

Runtime Snapshot

而 Web:

GET /api/fiveg/status
      │
      ▼
读取 Snapshot
      │
      ▼
返回 JSON

整个过程:

                ┌──────────────┐
                │    Modem     │
                └──────▲───────┘
                       │ AT
                       │
                ┌──────┴───────┐
                │ FiveGService │
                └──────┬───────┘
                       │
                       ▼
                Runtime Snapshot
                       ▲
                       │
Browser → API → StatusService

这样 HTTP Request 完全不需要等待硬件。

这是工业设备 Web 架构中非常重要的一点。


二十九、为什么不要在 API Handler 里直接做耗时硬件操作

假设:

app.MapGet(
    "/api/status",
    async () =>
    {
        var result =
            await modem.SendAsync("AT+C5GREG?");

        return Results.Ok(result);
    });

看起来没问题。

但实际上存在:

HTTP Request
    │
    ▼
等待 Serial Port
    │
    ▼
等待 Modem
    │
    ▼
AT Timeout

如果 modem 需要:

5 秒

整个 HTTP 请求就被占用 5 秒。

如果多个浏览器同时请求:

Request 1
Request 2
Request 3
Request 4

所有请求都可能去抢:

AT Channel

最终需要:

Command Queue
Lock
Timeout
Cancellation
Concurrency Control

复杂度迅速上升。


三十、Snapshot 模式

设备端状态查询比较推荐:

Producer
   │
   ▼
Snapshot
   ▲
   │
Consumer

例如:

FiveGService
    │
    │ 更新
    ▼
FiveGStatusSnapshot
    ▲
    │ 读取
    │
Web API

API:

app.MapGet(
    "/api/fiveg/status",
    (FiveGStatusService service) =>
    {
        return Results.Ok(
            service.GetSnapshot());
    });

请求执行时间就非常短:

读取内存
 ↓
JSON Serialize
 ↓
返回

而不是:

发 AT
 ↓
等待串口
 ↓
等待 Modem
 ↓
Parse
 ↓
返回

三十一、这也是 ASP.NET Core 和后台 Service 的边界

可以把职责划分为:

ASP.NET Core HTTP Layer
负责:

Request
Routing
Validation
Response

而:

Device Service Layer
负责:

Hardware
State Machine
Recovery
Polling
Timeout
Retry

这样形成:

HTTP
 ↓
Application Service
 ↓
Runtime Service
 ↓
Hardware

这个边界非常重要。


三十二、Minimal API 并不等于“没有架构”

很多人看到 Minimal API:

app.MapGet(...)

容易产生一种印象:

Minimal API 就是把所有代码写进 Program.cs。

这是错误的。

Minimal 的意思主要是:

Web API 编程模型更加轻量。

而不是:

应用架构也要最小化。

对于工业项目,我仍然建议:

Program.cs
│
├── Dependency Injection
├── Middleware
└── Endpoint Registration

真正业务逻辑:

Services
Domain
Infrastructure

分别维护。

例如:

Program.cs
    │
    ▼
Api
    │
    ▼
Services
    │
    ▼
Infrastructure

三十三、推荐结构

例如:

Stm32ConfigWeb
│
├── Program.cs
│
├── Api
│   ├── FiveGEndpoints.cs
│   ├── NetworkEndpoints.cs
│   └── SystemEndpoints.cs
│
├── Services
│   ├── FiveG
│   ├── Network
│   └── Configuration
│
├── Models
│
├── Infrastructure
│   ├── Linux
│   ├── Serial
│   └── Storage
│
└── wwwroot

Endpoint 文件:

public static class FiveGEndpoints
{
    public static void MapFiveGEndpoints(
        this WebApplication app)
    {
        app.MapGet(
            "/api/fiveg/status",
            GetStatus);
    }

    private static IResult GetStatus(
        FiveGStatusService service)
    {
        return Results.Ok(
            service.GetSnapshot());
    }
}

然后 Program.cs

var builder =
    WebApplication.CreateBuilder(args);

builder.Services
    .AddSingleton<FiveGStatusService>();

var app = builder.Build();

app.MapFiveGEndpoints();

app.Run();

这样 Minimal API 仍然可以保持良好的工程结构。


三十四、从源码思想看 ASP.NET Core

如果把大量实现细节拿掉,ASP.NET Core 核心其实没有想象中复杂。

可以抽象成:

Server
   │
   ▼
HttpContext
   │
   ▼
RequestDelegate
   │
   ▼
Middleware Chain
   │
   ▼
Endpoint
   │
   ▼
Application Code

最终最核心的思想就是:

对每一个 HttpContext 执行一条 RequestDelegate 链。

Minimal API、MVC、Razor Pages 都建立在这个基础之上。


三十五、一个极简版“ASP.NET Core”

如果自己模拟,可以想象有:

public delegate Task RequestDelegate(
    HttpContext context);

然后:

RequestDelegate endpoint =
    async context =>
    {
        await context.Response
            .WriteAsync("Hello");
    };

Middleware:

RequestDelegate pipeline =
    async context =>
    {
        Console.WriteLine("Before");

        await endpoint(context);

        Console.WriteLine("After");
    };

Server 收到 Request:

await pipeline(context);

这基本就是 ASP.NET Core Pipeline 最核心的抽象。

真正框架当然远比这个复杂,但思想就是如此。


三十六、性能为什么不错

ASP.NET Core 性能比较好的一个重要原因是:

整个请求链条相对直接

尤其 Minimal API:

Kestrel
 ↓
Routing
 ↓
Endpoint
 ↓
Handler

相比很多传统大型 Web Framework:

大量动态扫描
反射
复杂 Controller 生命周期
多层 Filter

整体执行路径比较轻量。

同时大量基础设施围绕:

async/await
ValueTask
Span<T>
Memory<T>
ArrayPool
Pipeline

进行性能优化。


三十七、嵌入式设备为什么更应该理解这些原理

普通企业 Web 项目:

32 GB RAM
16 Core CPU
Kubernetes
Cloud

很多性能浪费可能感知不到。

但设备端可能只有:

ARM Cortex-A
有限 RAM
有限 Flash
有限 CPU

因此你必须知道:

哪些对象长期存在
哪些操作会分配内存
哪些请求会阻塞
哪些 Service 是 Singleton
哪些逻辑运行在 BackgroundService
哪些数据只应该读取 Snapshot

这也是为什么在嵌入式设备上使用 ASP.NET Core 时:

理解框架底层原理,比单纯会写 API 更重要。


三十八、最终总结

回到最开始的问题:

当浏览器访问:

GET /api/status

ASP.NET Core 到底发生了什么?

完整过程是:

1. Browser 建立 TCP 连接

2. Kestrel 接收连接

3. Kestrel 解析 HTTP Request

4. ASP.NET Core 创建 HttpContext

5. Request 进入 Middleware Pipeline

6. Routing 根据 Path + Method 匹配 Endpoint

7. Minimal API 进行参数绑定

8. Dependency Injection 提供 Service

9. Endpoint Handler 执行业务逻辑

10. Handler 返回 IResult

11. System.Text.Json 序列化对象

12. ASP.NET Core 构建 HttpResponse

13. Kestrel 将 Response 写入 TCP

14. Browser 收到 JSON

因此我们平时写的:

app.MapGet(
    "/api/status",
    () => Results.Ok("Connected"));

虽然只有几行代码,但背后实际上是:

Host
+
Kestrel
+
HttpContext
+
Middleware
+
Routing
+
Endpoint
+
Dependency Injection
+
Serialization

共同完成的。

理解这一层以后,再看 ASP.NET Core 就不会只是:

MapGet
MapPost
Controller

而会真正理解:

ASP.NET Core 是一个围绕 HTTP Pipeline 构建的应用宿主框架。

对于我们这样的 Linux ARM64 工业设备项目,这一点尤其重要。

因为真正运行在 ASP.NET Core Host 中的不只是 Web API,还有:

配置服务
设备状态服务
5G 服务
后台轮询
状态机
恢复逻辑
Linux 系统访问

Web API 只是它对外暴露的一层接口。


下一篇

下一篇准备继续深入:

《ASP.NET Core BackgroundService 深度解析:为什么设备后台任务不能写在 HTTP API 里》

重点会讲:

IHostedService
BackgroundService
ExecuteAsync
CancellationToken
应用生命周期
异常传播
后台任务退出
线程池
async/await
定时轮询
设备状态机

并结合 Linux ARM64 设备上的 5G Modem 状态轮询,分析一种比较合理的工业设备后台任务架构。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/wojiuguowei/article/details/165474711

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--