我正在将应用程序从 Asp.net 控制器移植到 Asp.net Minimal-Apis。当前项目正在使用基于模型的 DataAnnotations。控制器进行开箱即用的模型验证,但 MinApi 则不然。
对于如下示例,在 MinimalApi 中进行 DataAnnotation 模型验证的最佳方法是什么?
数据注释模型示例:
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}";
}
带模型的最小 Api 示例:
accounts.MapPost("/saveAccount", (IAccountManager _accountManager, [FromBody] Account account) =>
{
var acct = _accountManager.SaveAccount(account);
return Results.Ok(acct);
})
这是我在 Minimal-Apis 中验证 DataAnnotation 模型的想法。请发布任何其他建议以改进或更好的替代方案。
辅助扩展方法:
using System.ComponentModel.DataAnnotations;
namespace minApi.Helpers.Extensions;
public static class DataValidator
{
public static (List<ValidationResult> Results, bool IsValid) DataAnnotationsValidate(this object model)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(model);
var isValid = Validator.TryValidateObject(model, context, results, true);
return (results, isValid);
}
}
验证器助手:
using Microsoft.AspNetCore.Mvc;
using minApi.Helpers.Extensions;
using System.Reflection;
namespace minApi.Helpers;
public static class CustomRouteHandlerBuilder
{
public static RouteHandlerBuilder Validate<T>(this RouteHandlerBuilder builder, bool firstErrorOnly = true)
{
builder.AddEndpointFilter(async (invocationContext, next) =>
{
var argument = invocationContext.Arguments.OfType<T>().FirstOrDefault();
var response = argument.DataAnnotationsValidate();
if (!response.IsValid)
{
string errorMessage = firstErrorOnly ?
response.Results.FirstOrDefault().ErrorMessage :
string.Join("|", response.Results.Select(x => x.ErrorMessage));
return Results.Problem(errorMessage, statusCode: 400);
}
return await next(invocationContext);
});
return builder;
}
}
Minimal-Api 方法中添加验证代码(最后一行):
accounts.MapPost("/saveAccount", (IAccountManager _accountManager, [FromBody] Account account) =>
{
var acct = _accountManager.SaveAccount(account);
return Results.Ok(acct);
})
.Validate<Account>();