Question

J'utilise le cadre de validation Fluent dans mon projet ASP.net MVC 3. Jusqu'à présent, tous mes ont été très validations simples (sûr que la chaîne est vide non seulement une certaine longueur, etc.), mais maintenant je dois vérifier que quelque chose existe dans la base de données ou non.

  1. doit validation Fluent être utilisé dans ce cas?
  2. Si la validation de base de données doit être effectuée à l'aide de validation Fluent, alors comment puis-je gérer les dépendances? Les classes de validateurs sont créés automatiquement, et je besoin de passer en quelque sorte l'un de mes instances du référentiel afin d'interroger ma base de données.

Un exemple de ce que je suis en train de valider la puissance:

J'ai une liste déroulante sur ma page avec une liste des éléments sélectionnés. Je veux confirmer que l'élément qu'ils ont choisi existe effectivement dans la base de données avant d'essayer d'enregistrer un nouveau record.

Modifier Voici un exemple de code d'une validation régulière Fluent cadre de 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();
    }
}

Contrôleur:

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

Comme vous pouvez le voir, je ne crée validateur moi-même. Cela fonctionne en raison de la ligne suivante dans Global.asax:

FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();

Le problème est que maintenant j'ai un validateur qui a besoin d'interagir avec ma base de données à l'aide d'un référentiel, mais comme je ne suis pas créer les validateurs Je ne sais pas comment je recevrais que la dépendance passée dans, autre que le hardcoding concrets.

Était-ce utile?

La solution

Ce lien peut vous aider à mettre en œuvre ce que vous cherchez sans avoir à instancier manuellement et manuellement vous valider les modèles. Ce lien est directement du forum de discussion FluentValidation.

Autres conseils

Tu ne peux pas créer votre propre méthode de validation où vous en kick-off la validation de la base de données?

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

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

J'utilise FluentValidation pour DataBase validations. il suffit de passer la classe de validation de la session dans le Ctor. et faire la validation à l'intérieur quelque chose d'action comme:

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

Mise à jour: Sur la base de votre exemple ajouter mon exemple ...

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

Deuxième mise à jour: Si vous insistez en utilisant constructeur parameterless vous devrez utiliser un INVERSION DU contrôle des conteneurs , une classe statique est quelque chose comme l'usine de vos objets. l'utiliser comme ceci:

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

    }
}

Vous pouvez trouver de nombreux conteneurs IoC, les plus célèbres sont Windsor et Ninject , Vous devrez Instruire le conteneur des registres ont une fois de résoudre toutes les ISession retourner votre objet de session.

L'autre façon que cela pourrait fonctionner pour vous utilise l'injection Constructor. Bien que cette méthode ne soit pas aussi claire que l'aide d'une bibliothèque IoC, il peut être utile si vous avez une façon statique d'accéder ou de récupérer votre 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...
    }
}

J'ai passé un peu de temps à penser à propos de cette même question exacte. J'utilise ninject pour injecter mon dépôt dans ma couche d'interface utilisateur Web pour que mon interface utilisateur Web la base de données accède uniquement via une interface.

Je suis désireux d'être en mesure de valider les choses qui ont accès à la base de données telles que la vérification des noms en double et donc mes besoins de validation pour accéder au référentiel injecté. Je pense que la meilleure façon de le faire est de configurer simplement Courant de validation via la méthode manuelle plutôt que la manière MVC intégrée. Par exemple:

Créez votre validation de classe (peut passer dans le référentiel 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;


    }
}

}

Ensuite, dans votre contrôleur, vous pouvez simplement créer une instance de classe au-dessus et de passer dans le référentiel (que ninject aurait injecté dans le constructeur du contrôleur)

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

Les deux fichiers ci-dessus peuvent vivre dans le projet et l'interface utilisateur Web vous pouvez aussi utiliser les DataAnnotations standards MVC pour la validation du côté client.

Juste pensé que je mettrais cela pour quelqu'un commentaire / help.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top