本文最后更新于 2024-12-09,文章内容可能已经过时。

在 ASP.NET Core 中,路由机制中间件是构建 Web 应用(包括 Web API 和 MVC 应用)的核心组件。理解它们的工作原理对于开发高效、可维护的应用至关重要。本文将详细讲解 .NET Core Web API 和 MVC 的路由机制,以及内置中间件(包括拦截器)等相关内容。

目录

  1. ASP.NET Core 路由机制概述

  2. MVC 和 Web API 的路由机制

  3. ASP.NET Core 中间件机制

  4. 中间件的执行顺序

  5. 示例:配置路由和中间件

  6. 总结


ASP.NET Core 路由机制概述

路由(Routing) 是 ASP.NET Core 应用程序中将请求的 URL 映射到相应的处理程序(例如控制器的动作方法)的过程。路由机制决定了请求如何被解析,并确定哪个控制器和动作方法将处理该请求。

ASP.NET Core 提供了灵活的路由系统,支持多种路由模式,包括约定路由和属性路由,并引入了端点路由(Endpoint Routing),进一步简化和优化了路由处理。

MVC 和 Web API 的路由机制

ASP.NET Core 的 MVC 和 Web API 使用相同的路由系统。尽管 Web API 和 MVC 在功能上有所不同,但在路由机制上它们共享大部分实现。

1. 路由的类型

ASP.NET Core 支持两种主要的路由类型:

1.1. 约定路由(Conventional Routing)

约定路由基于预定义的 URL 模式(模板),将请求映射到控制器和动作方法。它通常在 Startup.csConfigure 方法中通过 UseEndpointsMapControllerRoute 配置。

示例:

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

在上述示例中,URL 模式 {controller=Home}/{action=Index}/{id?} 表示:

  • controller:控制器名称,默认为 Home

  • action:动作方法名称,默认为 Index

  • id:可选参数

1.2. 属性路由(Attribute Routing)

属性路由通过在控制器和动作方法上直接使用路由属性来定义路由。它允许更细粒度和更具描述性的路由配置。

示例:

[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        // ...
    }
}

在上述示例中:

  • 控制器的路由为 api/products

  • 动作方法的路由为 api/products/{id}

属性路由通常用于 Web API,因为它可以清晰地定义资源的 RESTful 路径,但它同样适用于 MVC 应用。

2. 路由匹配流程

ASP.NET Core 的路由匹配流程如下:

  1. 请求进入中间件管道:每个请求通过注册的中间件按顺序进行处理。

  2. 路由中间件处理路由UseRouting 中间件负责解析请求的 URL 并匹配到路由模板。

  3. 执行授权和其他中间件:在路由匹配之后,可以执行授权(UseAuthorization)、CORS 等中间件。

  4. 端点执行UseEndpoints 中间件将匹配到的端点(控制器的动作方法)执行。

这个流程强调了中间件的顺序对于路由和应用行为的重要性。

3. 端点路由(Endpoint Routing)

ASP.NET Core 3.0 引入了端点路由,它将路由和终结点(Endpoints)集成在一起,提供更好的性能和灵活性。端点路由允许在路由解析后将终结点传递给其他中间件进行进一步处理。

主要特性:

  • 统一的路由系统:无论是 MVC、Razor Pages 还是 SignalR,所有都使用相同的路由系统。

  • 中间件集成:允许在路由解析后执行其他中间件,如授权。

  • 更好的性能:减少了不必要的路由解析和上下文切换。

ASP.NET Core 中间件机制

中间件是 ASP.NET Core 中用于处理 HTTP 请求和响应的组件。每个中间件都可以对请求进行处理、调用下一个中间件,或终止请求处理。

1. 中间件简介

中间件是按顺序执行的组件管道,每个中间件可以:

  • 处理请求

  • 修改请求或响应

  • 调用管道中的下一个中间件

  • 终止请求处理

ASP.NET Core 提供了丰富的内置中间件,也支持开发自定义中间件。

2. 内置中间件

ASP.NET Core 提供了多种内置中间件,以下是一些常用的内置中间件及其功能:

2.1. 身份验证和授权(Authentication and Authorization)

  • Authentication Middleware (UseAuthentication)

    • 负责识别用户身份。

    • 解析请求中的认证凭据(如 JWT、Cookie)。

    • 将用户信息添加到 HttpContext.User

  • Authorization Middleware (UseAuthorization)

    • 负责确定用户是否有权访问资源。

    • 基于策略、角色或声明进行授权检查。

示例:

app.UseAuthentication();
app.UseAuthorization();

2.2. 静态文件(Static Files)

  • Static Files Middleware (UseStaticFiles)

    • 提供对静态文件(如 HTML、CSS、JS、图像)的服务。

    • 默认从 wwwroot 目录提供静态文件。

示例:

app.UseStaticFiles();

高级配置:

可以配置静态文件的请求路径、缓存策略等。

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
    }
});

2.3. 路由(Routing)

  • Routing Middleware (UseRouting)

    • 负责匹配请求 URL 到路由模板。

    • 生成路由上下文。

  • Endpoints Middleware (UseEndpoints)

    • 负责执行匹配到的终结点(如控制器的动作方法)。

    • 需要在 UseRouting 之后调用。

示例:

app.UseRouting();

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

2.4. CORS 中间件

  • CORS Middleware (UseCors)

    • 允许或限制跨域请求。

    • 基于配置策略,定义哪些源、方法和头部被允许。

示例:

services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin",
        builder => builder.WithOrigins("https://example.com")
                          .AllowAnyMethod()
                          .AllowAnyHeader());
});

app.UseCors("AllowSpecificOrigin");

2.5. 日志记录(Logging)

  • Logging Middleware

    • 虽然不是传统意义上的中间件,但日志记录是通过中间件管道集成的。

    • 使用内置的日志记录提供程序(如 Console、Debug、Azure 等)记录应用程序的活动。

配置示例:

Program.csStartup.cs 中配置日志记录:

var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole();

2.6. 异常处理中间件(Exception Handling Middleware)

  • Exception Handling Middleware (UseExceptionHandler, UseDeveloperExceptionPage)

    • 捕获未处理的异常并生成相应的错误响应。

    • UseDeveloperExceptionPage 提供详细的错误页面,适用于开发环境。

    • UseExceptionHandler 提供生产环境下的错误处理逻辑。

示例:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

2.7. 响应压缩(Response Compression)

  • Response Compression Middleware (UseResponseCompression)

    • 压缩响应内容以减少带宽消耗。

    • 支持多种压缩算法(如 Gzip、Brotli)。

示例:

services.AddResponseCompression(options =>
{
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

app.UseResponseCompression();

3. 拦截器(Interceptors)

在 ASP.NET Core 中,拦截器 通常指的是能够在请求处理管道中拦截和处理请求的组件。这些拦截器可以通过中间件或其他机制实现。

3.1. 使用中间件实现拦截

通过自定义中间件,可以拦截请求和响应。例如,记录请求日志、修改请求内容等。

示例:自定义日志中间件

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger<RequestLoggingMiddleware>();
    }

    public async Task Invoke(HttpContext context)
    {
        _logger.LogInformation("Handling request: " + context.Request.Method + " " + context.Request.Path);
        await _next(context);
        _logger.LogInformation("Finished handling request.");
    }
}

// 在 Startup.cs 中注册中间件
app.UseMiddleware<RequestLoggingMiddleware>();

3.2. 使用过滤器(Filters)实现拦截

对于 MVC 和 Web API,可以使用 动作过滤器(Action Filters) 等过滤器来拦截请求。

示例:自定义动作过滤器

public class CustomActionFilter : IActionFilter
{
    private readonly ILogger _logger;

    public CustomActionFilter(ILogger<CustomActionFilter> logger)
    {
        _logger = logger;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation("Action executing: " + context.ActionDescriptor.DisplayName);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        _logger.LogInformation("Action executed: " + context.ActionDescriptor.DisplayName);
    }
}

// 在 Startup.cs 中注册过滤器
services.AddControllers(options =>
{
    options.Filters.Add<CustomActionFilter>();
});

注意: 过滤器主要用于 MVC 和 Web API 层面的拦截,而中间件用于全局的请求处理拦截。

4. 自定义中间件

除了内置中间件,开发者可以创建自定义中间件以满足特定需求。

示例:创建一个自定义中间件

public class CustomHeaderMiddleware
{
    private readonly RequestDelegate _next;

    public CustomHeaderMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // 在请求处理前添加自定义头
        context.Response.OnStarting(() =>
        {
            context.Response.Headers.Add("X-Custom-Header", "MyValue");
            return Task.CompletedTask;
        });

        await _next(context);
    }
}

// 在 Startup.cs 中注册中间件
app.UseMiddleware<CustomHeaderMiddleware>();

简化注册:使用扩展方法

public static class CustomHeaderMiddlewareExtensions
{
    public static IApplicationBuilder UseCustomHeader(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CustomHeaderMiddleware>();
    }
}

// 注册中间件
app.UseCustomHeader();

中间件的执行顺序

中间件在 ASP.NET Core 中按注册顺序执行。请求通过中间件管道时,按注册顺序从上到下依次进入每个中间件,然后按相反的顺序返回。

重要原则:

  • 顺序决定行为:中间件的执行顺序至关重要。例如,UseAuthentication 必须在 UseAuthorization 之前注册。

  • 短路中间件:某些中间件可能会终止请求处理,如静态文件中间件如果匹配到静态文件,会终止后续中间件的执行。

  • 异常处理:应将异常处理中间件(如 UseExceptionHandler)放在管道的最前面,以捕获所有后续中间件的异常。

示例:典型的中间件顺序

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseCors("AllowSpecificOrigin");

    app.UseAuthentication();
    app.UseAuthorization();

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

在上述示例中,中间件的注册顺序确保了异常处理、静态文件服务、路由解析、CORS、认证和授权等功能按预期工作。

示例:配置路由和中间件

下面是一个完整的示例,展示如何在 ASP.NET Core 应用中配置路由和中间件。

Program.cs(.NET 6 及以上的最简配置)

var builder = WebApplication.CreateBuilder(args);

// 添加服务到容器
builder.Services.AddControllers();

// 配置 CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin",
        builder => builder.WithOrigins("https://example.com")
                          .AllowAnyMethod()
                          .AllowAnyHeader());
});

// 添加日志记录
builder.Logging.ClearProviders();
builder.Logging.AddConsole();

// 构建应用
var app = builder.Build();

// 配置中间件管道
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseCors("AllowSpecificOrigin");

app.UseAuthentication();
app.UseAuthorization();

// 自定义中间件
app.Use(async (context, next) =>
{
    // 在请求处理前
    Console.WriteLine($"Handling request: {context.Request.Method} {context.Request.Path}");
    await next.Invoke();
    // 在请求处理后
    Console.WriteLine($"Finished handling request.");
});

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

app.Run();

示例控制器:ProductsController

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    // GET: api/products
    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok(new string[] { "Product1", "Product2" });
    }

    // GET: api/products/5
    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        return Ok($"Product {id}");
    }

    // POST: api/products
    [HttpPost]
    public IActionResult Create([FromBody] string product)
    {
        return CreatedAtAction(nameof(GetById), new { id = 1 }, product);
    }
}

在上述示例中:

  • 服务注册:添加了控制器服务和 CORS 策略。

  • 中间件配置:配置了异常处理、HTTPS 重定向、静态文件、路由、CORS、认证、授权和自定义中间件。

  • 路由:使用属性路由定义了 ProductsController 的 API 路径。

总结

ASP.NET Core 提供了强大且灵活的路由和中间件机制,使开发者能够构建高效、可扩展的 Web 应用程序。理解路由类型(约定路由和属性路由)、端点路由以及中间件的工作原理和注册顺序,对于构建健壮的应用至关重要。

关键要点:

  • 路由机制

    • 约定路由:基于预定义的 URL 模式映射控制器和动作方法。

    • 属性路由:通过在控制器和动作方法上定义路由属性,实现更细粒度的路由控制。

    • 端点路由:统一和优化的路由系统,支持所有终结点类型。

  • 中间件机制

    • 中间件按注册顺序执行,每个中间件可以处理请求、调用下一个中间件或终止请求。

    • 内置中间件涵盖了身份验证、授权、静态文件服务、CORS、日志记录等常用功能。

    • 可以通过自定义中间件和过滤器实现特定的请求拦截和处理逻辑。

通过合理配置路由和中间件,可以构建功能丰富、性能优良且易于维护的 ASP.NET Core 应用。