【问题标题】:Fluent Validation in ASP.net MVC - Database ValidationsASP.net MVC 中的流利验证 - 数据库验证
【发布时间】:2012-01-09 02:46:51
【问题描述】:

我在我的 ASP.net MVC 3 项目中使用 Fluent Validation 框架。到目前为止,我的所有验证都非常简单(确保字符串不为空,只有一定长度等),但现在我需要验证数据库中是否存在某些内容。

  1. 在这种情况下应该使用 Fluent Validation 吗?
  2. 如果数据库验证应该使用 Fluent Validation 来完成,那么我该如何处理依赖关系?验证器类是自动创建的,我需要以某种方式将它传递给我的存储库实例之一才能查询我的数据库。

我试图验证的一个例子可能是:

我的页面上有一个下拉列表,其中包含所选项目的列表。我想在尝试保存新记录之前验证他们选择的项目是否确实存在于数据库中。

编辑
以下是 Fluent Validation 框架中常规验证的代码示例:

[Validator(typeof(CreateProductViewModelValidator))]
public class CreateProductViewModel
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class CreateProductViewModelValidator : AbstractValidator<CreateProductViewModel>
{
    public CreateProductViewModelValidator()
    {
        RuleFor(m => m.Name).NotEmpty();
    }
}

控制器:

public ActionResult Create(CreateProductViewModel model)
{
    if(!ModelState.IsValid)
    {
        return View(model);
    }

    var product = new Product { Name = model.Name, Price = model.Price };
    repository.AddProduct(product);

    return RedirectToAction("Index");
}

如您所见,我从未自己创建验证器。这是因为Global.asax 中的以下行:

FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();

问题是现在我有一个验证器,它需要使用存储库与我的数据库交互,但由于我没有创建验证器,我不知道如何获取传递的依赖项,除了硬编码具体类型。

【问题讨论】:

  • 我添加了一个示例 hot 以在您的验证中使用会话依赖注入。希望它会有所帮助。附言不需要赏金就说你需要一个例子......
  • 除非你的例子没有给我我所要求的。我已经告诉过你,我自己不会创建验证器。它由 Fluent Validation 框架自动创建。 FluentValidation 需要一个默认的无参数构造函数,否则将无法创建验证器。
  • 已更新,您将不得不使用 IoC 容器在构造函数之外注入 Session 对象。

标签: asp.net-mvc fluentvalidation asp.net-mvc-validation


【解决方案1】:

我正在使用 FluentValidation 进行数据库验证。只需将验证类传递给Ctor 中的会话。并在操作中进行验证,例如:

var validationResult = new ProdcutValidator(session).Validate(product);

更新:根据您的示例,我添加了示例...

public class CreateProductViewModel
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
    private readonly ISession _session;
    public CreateProductViewModelValidator(ISession session)
    {
        _session = session;
        RuleFor(m => m.Name).NotEmpty();
        RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);

    }
}
Controller:

public ActionResult Create(CreateProductViewModel model)
{
    var validator = new CreateProductViewModelValidator();
    var validationResult =validator.Validate(model);

    if(!validationResult.IsValid)
    {
        // You will have to add the errors by hand to the ModelState's errors so the
        // user will be able to know why the post didn't succeeded(It's better writing 
        // a global function(in your "base controller" That Derived From Controller)
        // that migrate the validation result to the 
        // ModelState so you could use the ModelState Only.
        return View(model);
    }

    var product = new Product { Name = model.Name, Price = model.Price };
    repository.AddProduct(product);

    return RedirectToAction("Index");
}

第二次更新:
如果您坚持使用无参数构造函数,您将不得不使用一些Inversion Of control container,这是一个类似于对象工厂的静态类。 像这样使用它:

public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
    private readonly ISession _session;
    public CreateProductViewModelValidator()
    {
        _session = IoC.Container.Reslove<ISession>();
        RuleFor(m => m.Name).NotEmpty();
        RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);

    }
}

你可以找到很多 IoC 容器,最著名的是 WindsorNinject, 您将需要注册 - 指示容器一次解析所有 ISession 以返回您的会话对象。

【讨论】:

  • 我从不手动创建验证器。这由 Fluent Validation 为我处理。
【解决方案2】:

您不能创建自己的验证方法,然后在其中启动数据库验证吗?

    RuleFor(m => m.name)
           .Must(BeInDatabase)

    private static bool BeInDatabase(string name)
    {
        // Do database validation and return false if not valid
        return false;
    }

【讨论】:

    【解决方案3】:

    这个link 可以帮助您实现您正在寻找的东西,而无需手动实例化和手动验证您的模型。此链接直接来自 FluentValidation 论坛。

    【讨论】:

    • 这正是我想要的。我需要创建一个ValidatorFactory。谢谢!
    • 查看线程后发现有一个 NuGet 包已经有一个 Ninject 验证器工厂。
    • 链接已失效。
    • 应该提供代码示例以及链接,链接现在已经失效,这个答案不再有用。
    • 链接已被Wayback机器当时记录:Inject a Repository in Validator, is it possible ?
    【解决方案4】:

    这可能对您有用的另一种方法是使用构造函数注入。虽然这种方法不像使用 IoC 库那样明确,但如果您有访问或获取会话的静态方式,它可能会有所帮助。

    public class CreateProductViewModelValidator
    {
        private ISession _session;
    
        public CreateProductViewModelValidator()
            :this(SessionFactory.GetCurrentSession()) //Or some other way of fetching the repository.
        {
    
        }
    
        internal CreateProductViewModelValidator(ISession session)
        {
            this._session = session;
            RuleFor(m => m.Name);//More validation here using ISession...
        }
    }
    

    【讨论】:

      【解决方案5】:

      我一直在思考这个完全相同的问题。我正在使用 ninject 将我的存储库注入我的 Web UI 层,以便我的 Web UI 仅通过接口访问数据库。

      我希望能够验证访问数据库的内容,例如检查重复名称,因此我的验证需要访问注入的存储库。我认为最好的方法是通过手动方法而不是 MVC 集成方式设置 Fluent Validation。例如:

      创建你的验证类(可以传入存储库接口):

      public class CategoryDataBaseValidation : AbstractValidator<CategoryViewModel>
      {
      
          private IRepository repository;
      
          public CategoryDataBaseValidation (IRepository repoParam) 
          {
      
              repository = repoParam;
      
              RuleFor(Category => Category.Name).Must(NotHaveDuplicateName).WithMessage("Name already exists");
          }
      
          private bool NotHaveDuplicateName(string name) 
          {
      
             List<Category> c = repository.Categories.ToList(); //Just showing that you can access DB here and do what you like.
             return false;
      
      
          }
      }
      

      }

      然后在您的控制器中,您只需创建上述类的实例并传入存储库(ninject 将在控制器构造函数中注入)

       [HttpPost]
          public ActionResult Create(CategoryViewModel _CategoryViewModel )
          {
      
              CategoryDataBaseValidation validator = new CategoryDataBaseValidation (repository);
      
              ValidationResult results = validator.Validate(_CategoryViewModel );
      
             if (results.IsValid == false)
              {
      
                  foreach (var failure in results.Errors)
                  {
      
                    //output error
      
                  }
      
              }
      
              return View(category);
          }
      

      上述两个文件都可以存在于 Web UI 项目中,然后您也可以只使用标准 MVC DataAnnotations 进行客户端验证。

      只是想我会发表评论/帮助某人。

      【讨论】:

        猜你喜欢
        • 2019-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-03
        相关资源
        最近更新 更多