ZetCode

ASP.NET ActionFilter

最后修改于 2025 年 4 月 3 日

在本文中,我们将探讨 ASP.NET 8 中的 ActionFilters。ActionFilters 允许您在控制器操作执行之前或之后运行代码。它们对于处理横切关注点非常强大。

ASP.NET 是一个跨平台、高性能的框架,用于构建现代 Web 应用程序。ActionFilters 提供了一种在操作级别实现类似中间件行为的方法。

基本定义

ASP.NET 中的 ActionFilter 是一个实现 IActionFilter 或 IAsyncActionFilter 接口的特性。它会拦截对控制器操作的请求。

ActionFilters 可以在操作运行之前 (OnActionExecuting) 和完成之后 (OnActionExecuted) 执行代码。它们对于日志记录、验证或修改响应非常有用。

ASP.NET 中的过滤器在一个称为过滤器管道的管道中运行。ActionFilters 在授权过滤器之后,但在结果过滤器和异常过滤器之前执行。

ASP.NET ActionFilter 示例

下面的示例演示了如何创建和使用自定义 ActionFilter 来记录请求信息。

Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();
app.Run();

这设置了一个基本的 ASP.NET 应用程序,并支持控制器。MapControllers 方法为控制器启用属性路由。

Filters/LogActionFilter.cs
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;

public class LogActionFilter : IActionFilter
{
    private readonly ILogger<LogActionFilter> _logger;

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

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation($"Action {context.ActionDescriptor.DisplayName} " +
            $"is executing at {DateTime.UtcNow}");
        
        // You can access action arguments
        foreach (var arg in context.ActionArguments)
        {
            _logger.LogInformation($"Argument: {arg.Key} = {arg.Value}");
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        var elapsed = Stopwatch.GetTimestamp();
        _logger.LogInformation($"Action {context.ActionDescriptor.DisplayName} " +
            $"completed at {DateTime.UtcNow}");
        
        if (context.Exception != null)
        {
            _logger.LogError(context.Exception, "Action threw an exception");
        }
    }
}

这个自定义 ActionFilter 会在操作执行前后记录信息。它演示了如何访问操作参数和处理异常。

Controllers/ProductsController.cs
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
[ServiceFilter(typeof(LogActionFilter))]
public class ProductsController : ControllerBase
{
    private static List<Product> _products = new()
    {
        new Product(1, "Laptop", 999.99m),
        new Product(2, "Mouse", 19.99m),
        new Product(3, "Keyboard", 49.99m)
    };

    [HttpGet]
    public IActionResult GetAllProducts()
    {
        return Ok(_products);
    }

    [HttpGet("{id}")]
    public IActionResult GetProductById(int id)
    {
        var product = _products.FirstOrDefault(p => p.Id == id);
        if (product == null) return NotFound();
        return Ok(product);
    }
}

public record Product(int Id, string Name, decimal Price);

控制器使用 [ServiceFilter] 特性应用 LogActionFilter。这可以确保依赖注入对过滤器的构造函数有效。

当此控制器中的任何操作运行时,过滤器都会记录执行详细信息。该示例展示了 ActionFilters 如何在不修改操作方法的情况下添加横切行为。

对于全局注册,您可以在 Program.cs 中添加过滤器:builder.Services.AddControllers(options => options.Filters.Add<LogActionFilter>()); 这会将过滤器应用于所有控制器。

来源

Microsoft ASP.NET Filters 文档

在本文中,我们探讨了 ASP.NET 8 中的 ActionFilters。这些强大的组件有助于以清晰且可维护的方式实现横切关注点。

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 ASP.NET 教程