5

我在我的 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();

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

4

5 回答 5

1

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

于 2011-12-08T15:11:55.683 回答
0

我正在使用 FluentValidation 进行数据库验证。只需将 Validation 类传递给 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 以返回您的会话对象。

于 2011-11-29T21:48:12.017 回答
0

难道你不能创建你自己的验证方法来启动数据库验证吗?

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

    private static bool BeInDatabase(string name)
    {
        // Do database validation and return false if not valid
        return false;
    }
于 2011-12-08T10:14:49.277 回答
0

这可能对您有用的另一种方法是使用构造函数注入。虽然这种方法不像使用 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...
    }
}
于 2011-12-09T04:32:20.863 回答
0

我已经花了很多时间思考这个完全相同的问题。我正在使用 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 进行客户端验证。

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

于 2013-05-02T00:44:23.163 回答