.NET 自定义过滤器 - ActionFilterAttribute
这个代码片段定义了一个自定义的 ASP.NET Core 过滤器(GuardModelStateAttribute
),用于在控制器动作执行之前验证模型状态(ModelState
)。如果模型状态无效,则构造一个 ProblemDetails
对象来描述错误,并返回一个 BadRequest
响应。
代码片段:
/// <summary>
/// 验证 ModelState 是否有效
/// </summary>
public class GuardModelStateAttribute : ActionFilterAttribute
{
// <summary>
/// 在执行操作之前进行验证。
/// 如果模型状态无效,则返回 BadRequest 响应。
/// </summary>
/// <param name="context">Action 执行上下文</param>
public override void OnActionExecuting(ActionExecutingContext context)
{
// 验证 ModelState 是否有效
if (!context.ModelState.IsValid)
{
// 构造 ProblemDetails 对象来构建错误响应
var problemDetails = new ProblemDetails
{
Title = "Bad Request", // 错误标题
Detail = "参数验证失败,请检查输入参数", // 错误详情
Status = (int)HttpStatusCode.BadRequest, // HTTP 状态码
Instance = context.HttpContext.Request.Path, // 请求路径
};
// 遍历 ModelState 字典,将错误信息添加到 Extensions 字典中
foreach (var key in context.ModelState.Keys)
{
// 获取每个键对应的错误信息
var errors = context.ModelState[key]?.Errors;
// 如果没有错误信息,则跳过
if (errors is not { Count: > 0 }) continue;
// 遍历每个错误,并将其添加到 ProblemDetails 的 Extensions 字典中
foreach (var error in errors)
{
problemDetails.Extensions.Add(key, error.ErrorMessage);
}
}
// 设置响应结果
context.Result = new BadRequestObjectResult(problemDetails);
}
}
}
代码解读
-
类定义:
public class GuardModelStateAttribute : ActionFilterAttribute
GuardModelStateAttribute
继承自ActionFilterAttribute
,这是一个内置的过滤器接口,用于在执行控制器动作前后执行一些逻辑。
-
覆盖
OnActionExecuting
方法:public override void OnActionExecuting(ActionExecutingContext context)
OnActionExecuting
方法是在控制器动作执行之前调用的。覆盖这个方法可以让我们在动作执行前做一些预处理工作。
-
验证模型状态:
if (!context.ModelState.IsValid)
ModelState.IsValid
是一个布尔属性,表示模型状态是否有效。如果为false
,表示模型状态无效,即请求中的数据未通过验证。
-
构造
ProblemDetails
对象:var problemDetails = new ProblemDetails { Title = "Bad Request", Detail = "参数验证失败,请检查输入参数", Status = (int)HttpStatusCode.BadRequest, Instance = context.HttpContext.Request.Path, };
ProblemDetails
是一个标准的对象,用于描述 HTTP 错误响应。这里设置了错误标题、详细信息、HTTP 状态码(400 Bad Request)以及请求的路径。
-
收集并附加错误信息:
foreach (var key in context.ModelState.Keys) { var errors = context.ModelState[key]?.Errors; if (errors is not { Count: > 0 }) continue; foreach (var error in errors) { problemDetails.Extensions.Add(key, error.ErrorMessage); } }
- 遍历
ModelState
中的所有键值对,获取每个字段的验证错误信息,并将这些错误信息添加到ProblemDetails
的Extensions
字典中。
- 遍历
-
设置响应结果:
context.Result = new BadRequestObjectResult(problemDetails);
- 设置
ActionExecutingContext
的Result
属性,返回一个包含ProblemDetails
的BadRequestObjectResult
,这将导致控制器不再继续执行,并返回一个带有错误信息的 HTTP 响应。
- 设置
作用
这个自定义过滤器的作用是:
- 验证模型状态:在控制器动作执行之前验证请求中的数据是否满足验证规则。
- 返回错误响应:如果数据验证失败,则构造一个包含详细错误信息的
ProblemDetails
对象,并返回一个BadRequest
响应。 - 简化错误处理:通过在过滤器中集中处理模型状态验证,可以减少在每个控制器动作中重复编写类似的错误处理逻辑。
使用方法
// Add services to the container.
#region 向容器中添加服务
// 关闭默认模型验证过滤器
builder.Services.Configure<ApiBehaviorOptions>(options => options.SuppressModelStateInvalidFilter = true);
builder.Services.AddControllers(options =>
{
// 添加过滤器
options.Filters.Add<GuardModelStateAttribute>();
})
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; //格式化时间
});
#endregion
要在控制器中使用这个过滤器,可以在控制器或动作方法上添加 [GuardModelState]
属性:
[ApiController]
[Route("[controller]")]
[GuardModelState] // 在控制器级别应用过滤器
public class MyController : ControllerBase
{
[HttpGet("{id}")]
public ActionResult Get(int id)
{
// 控制器逻辑
return Ok();
}
[HttpPost]
[GuardModelState] // 在动作方法级别应用过滤器
public ActionResult Post([FromBody] MyModel model)
{
// 控制器逻辑
return Ok();
}
}
总结
GuardModelStateAttribute
是一个自定义的 ASP.NET Core 过滤器,用于在控制器动作执行前验证模型状态,并在模型状态无效时返回一个带有详细错误信息的 BadRequest
响应。通过使用这个过滤器,可以简化错误处理逻辑,并提高代码的可维护性和可读性。