请求验证
Sharkable 集成了 FluentValidation,为 ISharkEndpoint 端点提供自动请求验证。启用后,传入的参数会与已注册的 IValidator<T> 进行匹配验证,无效请求会返回包含 UnifiedResult 错误信息的 400 响应。
启用
builder.Services.AddShark(opt =>
{
opt.EnableValidation = true;
});
创建验证器
继承 AbstractValidator<T> 定义验证规则:
using FluentValidation;
public class CreateUserRequest
{
public string Name { get; set; }
public string Email { get; set; }
}
public class CreateUserValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserValidator()
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
RuleFor(x => x.Email).NotEmpty().EmailAddress();
}
}
注册验证器
非 AOT 模式(自动扫描)
启用 EnableValidation = true 后,Sharkable 会自动扫描已注册程序集中所有 IValidator<T> 的实现并注册。
AOT 模式(手动注册)
AOT 模式下无法使用程序集扫描,需要手动注册:
builder.Services.AddSingleton<IValidator<CreateUserRequest>, CreateUserValidator>();
工作原理
启用并注册后,所有 ISharkEndpoint 的参数如果存在对应的 IValidator<T> 注册在 DI 中,都会在处理前自动验证。
public class UserEndpoint : ISharkEndpoint
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapPost("create", (CreateUserRequest request) =>
{
// 如果请求无效,验证过滤器会在到达此处前返回 400 错误
return Results.Ok("valid!");
});
}
}
成功响应
{
"statusCode": 200,
"data": "valid!",
"errorMessage": null
}
验证错误响应
{
"statusCode": 400,
"data": null,
"errorMessage": "'Name' must not be empty.; 'Email' must not be empty."
}
AOT 完整示例
using System.Text.Json.Serialization;
using FluentValidation;
using Sharkable;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddShark([typeof(Program).Assembly], opt =>
{
opt.EnableValidation = true;
});
// AOT 下需要手动注册验证器
builder.Services.AddSingleton<IValidator<CreateUserRequest>, CreateUserValidator>();
// 注册 JsonSerializerContext 以支持 AOT 序列化
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default);
});
var app = builder.Build();
app.UseShark();
app.Run();
public record CreateUserRequest(string Name, string Email);
public class CreateUserValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserValidator()
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
RuleFor(x => x.Email).NotEmpty().EmailAddress();
}
}
[JsonSerializable(typeof(CreateUserRequest))]
internal partial class AppJsonContext : JsonSerializerContext { }