C# EF核心Web API:外键验证

C# EF核心Web API:外键验证,c#,database,validation,asp.net-core,entity-framework-core,C#,Database,Validation,Asp.net Core,Entity Framework Core,假设我有这些课程: 公共类用户 { 公共int?Id{get;set;} ... } 公务舱钱包 { 公共int?Id{get;set;} 公共字符串标题{get;set;} 公共用户所有者{get;set;} ... } 公共级WalletCreationTo { [必需] 公共字符串标题{get;set;} [必需] public int OwnerId{get;set;} } [HttpPost] 公共异步任务CreateWallet(WalletCreationTo walletDTO)

假设我有这些课程:

公共类用户
{
公共int?Id{get;set;}
...
}
公务舱钱包
{
公共int?Id{get;set;}
公共字符串标题{get;set;}
公共用户所有者{get;set;}
...
}
公共级WalletCreationTo
{
[必需]
公共字符串标题{get;set;}
[必需]
public int OwnerId{get;set;}
}
[HttpPost]
公共异步任务CreateWallet(WalletCreationTo walletDTO){…}
我必须向前端报告任何错误参数,如下所示:

{
“错误”:{
“ownerId”:“按Id的用户不存在”,
“标题”:“不得超过8个字符”
}  
}
如何验证所有者ID

  • 手动查询数据库似乎无效
  • 默认的ASP.NET核心验证似乎没有任何与数据库访问相关的注释

您可以在简单模式下使用此选项

        [HttpPost]
        public async Task<ActionResult> CreateWallet(WalletCreationDto walletDTO)
        {
            bool isValidOwnerId = /*validationLogic => can use service or Repository or etc... */

            if (isValidOwnerId == false)
                ModelState.AddModelError("OwnerId", "errorMessage");


            if (ModelState.IsValid)
            {
                //CreateWallet Loigc......
            }

            //we can get all errors from ModelState
            List<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors).ToList();

            /*
             return .... 
            */
        }
[HttpPost]
公共异步任务


:用于构建强类型验证规则的流行.NET库。

我最终使用了fluent验证。这不是实现这一点的最有效的方法,但我正在权衡漂亮的错误和简单的代码

public class WalletCreateDTO
{
    [Required]
    [MaxLength(20)]
    public string Title { get; set; }

    [Required]
    public int OwnerId { get; set; }

    [Required]
    public string CurrencyCode { get; set; }
}

public class WalletCreateDTOValidator : AbstractValidator<WalletCreateDTO>
{
    public WalletCreateDTOValidator(Data.Database database)
    {
        this.RuleFor(w => w.OwnerId)
            .Must(ownerId => database.Users.Any(user => user.Id == ownerId))
            .WithMessage("User does not exist");
        this.RuleFor(w=> w.CurrencyCode)
            .Must(currencyCode => database.Currencies.Any(currency => currency.Code == currencyCode))
            .WithMessage("Currency does not exist");
    }
}
注意:这似乎注册了程序集中的所有验证器。例如,我的所有DTO都在Api.DTOs目录/名称空间中,并且似乎都注册了,这很方便


此外,还有一个招摇过市的集成:
微元素。招摇过市。FluentValidation

我建议您尝试FluentValidation。对于服务器端验证,我发现它非常有用。请注意,这不是广告。在控制器中包含流畅的验证似乎很好,但似乎很混乱,因为我正在使用dabatase Context进行验证。您可以创建一个自定义验证器(实现IValidation)并执行检查,看起来很混乱,尽管我需要对其他服务的引用,这些服务只用于验证一个属性。似乎真的没有办法利用数据库自己的方式来验证输入如果你指的是“数据库自己的方式”,这是=>
\u context.Users.Any(e=>e.Id==OwnerId),可以使用相同的方法(_上下文类型可以是DbContext或IdentityDbContext)
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddFluentValidation(config =>
        {
            config.RegisterValidatorsFromAssembly(typeof(WalletCreateDTO).Assembly);
        });
}