You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在ASP.NET Minimal API中使用DataAnnotation模型验证的最佳方案

在ASP.NET Minimal API中实现DataAnnotations模型验证的最佳方案

你正在从ASP.NET Controllers迁移到Minimal API,原项目依赖基于DataAnnotations的模型验证,但Minimal API默认不提供该能力。以下是几种适配你场景的实用实现方案:

示例模型与原端点代码

数据注解模型

using System.ComponentModel.DataAnnotations;

namespace minApi.Models;

public class Account
{
  [Required]
  public int AccountId { get; set; }

  [Required, MaxLength(50)]
  public string AccountName { get; set; };

  [Required, EmailAddress]
  public string AccountEmail { get; set; };

  [Required, Phone]
  public string AccountPhone { get; set; };

  [Required, MaxLength(50)]
  public string StreetAddress { get; set; };

  [Required, MaxLength(50)]
  public string City { get; set; };

  [Required, MaxLength(2)]
  public string StateProvince { get; set; };

  [Required, MaxLength(10)]
  public string PostalCode { get; set; };

  public bool IsActive { get; set; } = true;

  public override string ToString() => $"{AccountName} AccountId: {AccountId}";
}

原Minimal API端点

accounts.MapPost("/saveAccount", (IAccountManager _accountManager, [FromBody] Account account) =>
{
    var acct = _accountManager.SaveAccount(account);

    return Results.Ok(acct);
})

方案1:手动验证(适合少量端点)

直接在端点逻辑中调用Validator.TryValidateObject完成验证,返回标准验证问题响应:

accounts.MapPost("/saveAccount", (IAccountManager _accountManager, [FromBody] Account account) =>
{
    var validationResults = new List<ValidationResult>();
    var isValid = Validator.TryValidateObject(
        account, 
        new ValidationContext(account), 
        validationResults, 
        validateAllProperties: true);

    if (!isValid)
    {
        return Results.ValidationProblem(validationResults.ToDictionary(
            vr => vr.MemberNames.FirstOrDefault() ?? string.Empty,
            vr => new[] { vr.ErrorMessage }));
    }

    var acct = _accountManager.SaveAccount(account);
    return Results.Ok(acct);
})

方案2:自定义验证扩展(复用性高)

封装验证逻辑为扩展方法,可在多个端点复用,保持代码简洁:

第一步:编写扩展方法

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

public static class ValidationExtensions
{
    public static RouteHandlerBuilder Validate<T>(this RouteHandlerBuilder builder)
    {
        return builder.AddEndpointFilter(async (context, next) =>
        {
            var model = context.Arguments.OfType<T>().FirstOrDefault();
            if (model == null)
            {
                return Results.BadRequest("无法获取待验证的模型");
            }

            var validationResults = new List<ValidationResult>();
            var isValid = Validator.TryValidateObject(
                model, 
                new ValidationContext(model), 
                validationResults, 
                validateAllProperties: true);

            if (!isValid)
            {
                return Results.ValidationProblem(validationResults.ToDictionary(
                    vr => vr.MemberNames.FirstOrDefault() ?? string.Empty,
                    vr => new[] { vr.ErrorMessage }));
            }

            return await next(context);
        });
    }
}

第二步:在端点中使用

accounts.MapPost("/saveAccount", (IAccountManager _accountManager, [FromBody] Account account) =>
{
    var acct = _accountManager.SaveAccount(account);
    return Results.Ok(acct);
})
.Validate<Account>(); // 添加此行启用验证

方案3:全局验证过滤器(全端点自动生效)

如果所有端点都需要模型验证,可注册全局端点过滤器,一次配置全量生效:

// 在Program.cs的服务配置中添加
builder.Services.AddSingleton<EndpointFilterDelegate>(async (context, next) =>
{
    foreach (var arg in context.Arguments)
    {
        if (arg == null) continue;

        var validationResults = new List<ValidationResult>();
        var isValid = Validator.TryValidateObject(
            arg, 
            new ValidationContext(arg), 
            validationResults, 
            validateAllProperties: true);

        if (!isValid)
        {
            return Results.ValidationProblem(validationResults.ToDictionary(
                vr => vr.MemberNames.FirstOrDefault() ?? string.Empty,
                vr => new[] { vr.ErrorMessage }));
        }
    }

    return await next(context);
});

方案选择建议

  • 手动验证:适合仅少数端点需要验证的场景,快速实现无需额外代码
  • 自定义扩展:适合多个端点复用验证逻辑,兼顾灵活性与代码整洁度
  • 全局过滤器:适合项目中所有端点都需要模型验证的场景,一次配置省心高效

内容的提问来源于stack exchange,提问作者WillC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:55:22