Free Validation in ASP.net MVC - Database Validation

I use the Fluent Validation framework in my ASP.net MVC 3 project. So far, all my checks have been very simple (make sure the string is not empty, only a certain length, etc.), but now I need to check that something it exists in the database or not.

  • Should Fluent Validation be used in this case?
  • If database validation should be done using Fluent Validation, then how do I handle dependencies? Validator classes are created automatically, and I need to somehow pass it to one of my repository instances to query my database.

An example of what I'm trying to verify might be:

I have a drop-down list on my page with a list of selected items. I want to confirm that the item they selected actually exists in the database before trying to save a new record.

Edit
Here is an example of a regular check code in Fluent Validation Fluct:

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

Controller:

 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"); } 

As you can see, I never create a validator myself. This works because of the following line in Global.asax :

 FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure(); 

The problem is that now I have a validator that needs to interact with my database using the repository, but since I do not create validators, I do not know how to get this dependent information, except for hard encoding. concrete type.

+4
source share
5 answers

I am using FluentValidation to check the database. just pass the Validation class session to Ctor. and do a check inside the action like this:

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

Update: Based on your example, I am adding my example ...

 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 errors so the // user will be able to know why the post didn't succeeded(It 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"); } 

Second update:
If you insist on using a constructor without parameters, you will have to use Inversion Control control , a static class that looks like the Factory of your objects, use it like this:

 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); } } 

You can find many IoC containers, the most famous of Windsor and Ninject , you will need to register - show the container once to allow all ISessions to return your session object.

0
source

Can't you just create your own validation method, where could you start the database validation?

  RuleFor(m => m.name) .Must(BeInDatabase) private static bool BeInDatabase(string name) { // Do database validation and return false if not valid return false; } 
0
source

Another way this may work for you is to use constructor injection. Although this method is not as simple as using the IoC library, it can help if you have a static way to access or receive a session.

 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
source

I spent a lot of time thinking about the same problem. I use ninject to enter my repository into my web interface so that my web interface only accesses the database through the interface.

I want to be able to check things that access the database, such as checking for duplicate names, and therefore, my checking requires access to the nested repository. I think the best way to do this is to simply configure Fluent Validation using a manual method rather than an integrated MVC method. For instance:

Create your verification class (can pass in the repository interface):

 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; } } 

}

Then in your controller, you can simply create an instance of the above class and pass it to the repository (this ninject will be entered into the controller’s constructor)

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

Both of the above files can work in a web interface project, and then you can simply use standard MVC DataAnnotations for client-side validation.

Just thought I posted this for comment / help to someone.

0
source

Source: https://habr.com/ru/post/1383706/


All Articles