2011-11-29 79 views
4

我在我的ASP.net MVC 3項目中使用Fluent驗證框架。到目前爲止,我所有的驗證都非常簡單(確保字符串不是空的,只有一定的長度等等),但是現在我需要驗證數據庫中是否存在或不存在。在ASP.net MVC流利的驗證 - 數據庫驗證

  1. 在這種情況下應該使用Fluent Validation嗎?
  2. 如果數據庫驗證應該使用Fluent驗證完成,那麼我該如何處理依賴關係?驗證器類是自動創建的,我需要以某種方式將它傳遞給我的一個存儲庫實例以查詢我的數據庫。

的什麼,我試圖驗證實力的一個例子:

我有一個下拉列表,我的網頁上選擇的項目列表。我想在嘗試保存新記錄之前驗證它們選擇的項目實際上存在於數據庫中。

編輯
這裏是流利的驗證框架定期驗證的代碼示例:

[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(); 

的問題是,現在我有一個需要使用存儲庫與我的數據庫交互的驗證,但因爲我沒有創建驗證我不知道我將如何獲得傳入的依賴關係,而不是對具體類型進行硬編碼。

+0

我在驗證中添加了一個很熱的例子來使用會話依賴注入。希望它會有所幫助。附:不需要賞金只是說你需要一個例子... – gdoron

+0

除了你的榜樣不給我我所要求的。我已經告訴過你,我不會自己創建驗證器。它由Fluent驗證框架自動創建。 FluentValidation需要一個默認的無參數構造函數,否則將無法創建驗證器。 – Dismissile

+0

已更新,您將不得不使用IoC容器將Session對象注入構造函數之外。 – gdoron

回答

1

link可以幫助你實現你無需手動實例化和手工驗證你的模型在找什麼。此鏈接直接來自FluentValidation論壇。

+0

這正是我一直在尋找。我需要創建一個ValidatorFactory。謝謝! – Dismissile

+0

查看線程後發現有一個NuGet包已經有Ninject驗證器工廠。 – Dismissile

+0

很高興能幫到您 – mreyeros

0

我正在使用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,這是一個類似於對象的Factory的靜態類。 這樣使用它:

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來回報您的會話對象。

+0

我永遠不會手動創建我的驗證器。這是通過Fluent驗證來處理的。 – Dismissile

+1

@Dismissile讓我看看你的代碼 – gdoron

+0

用一些代碼更新了我的文章。 – Dismissile

0

難道你不能只是創建自己的驗證方法,你會在哪裏啓動數據庫驗證?

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

    private static bool BeInDatabase(string name) 
    { 
     // Do database validation and return false if not valid 
     return false; 
    } 
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... 
    } 
} 
0

我一直花費相當多的時間思考這個完全相同的問題。我正在使用ninject將我的資源庫注入到我的Web UI層,以便我的Web UI只通過一個接口訪問數據庫。

我希望能夠驗證訪問數據庫,如檢查重複的名稱,因此我的驗證需要訪問庫注入的東西。我認爲最好的方法就是通過手動方法設置Fluent Validation,而不是MVC集成方式。例如:

創建您的驗證類(可以在庫接口傳遞):

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。

只是想,我會把這件事的意見/幫助別人。