Frage

Ich verwende das fließende Validierungsframework in meinem ASP.NET MVC 3 -Projekt. Bisher waren alle meine Bestätigungen sehr einfach (stellen Sie sicher, dass die Zeichenfolge nicht leer ist, nur eine bestimmte Länge usw.), aber jetzt muss ich überprüfen, dass in der Datenbank etwas vorhanden ist oder nicht.

  1. Sollte in diesem Fall eine fließende Validierung verwendet werden?
  2. Wenn die Datenbankvalidierung unter Verwendung einer fließenden Validierung durchgeführt werden sollte, wie gehe ich dann mit Abhängigkeiten um? Die Validator -Klassen werden automatisch erstellt, und ich müsste sie irgendwie eine meiner Repository -Instanzen übergeben, um meine Datenbank abzufragen.

Ein Beispiel für das, was ich zu validieren versuche, könnte:

Ich habe eine Dropdown -Liste auf meiner Seite mit einer Liste ausgewählter Elemente. Ich möchte validieren, dass das von ihnen ausgewählte Element tatsächlich in der Datenbank vorhanden ist, bevor Sie versuchen, einen neuen Datensatz zu speichern.

Bearbeiten
Hier ist ein Code -Beispiel für eine regelmäßige Validierung im Fluent -Validierungsrahmen:

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

Regler:

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

Wie Sie sehen können, erstelle ich den Validator nie selbst. Dies funktioniert aufgrund der folgenden Zeile in Global.asax:

FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();

Das Problem ist, dass ich jetzt einen Validator habe, der mit meiner Datenbank mit einem Repository interagieren muss, aber da ich nicht die Validatoren erstelle, weiß ich nicht, wie ich diese Abhängigkeit übergeben würde, außer dem konkreten Typ.

War es hilfreich?

Lösung

Dies Verknüpfung Kann Ihnen helfen, das zu implementieren, wonach Sie suchen, ohne Ihre Modelle manuell zu instanziieren und manuell zu validieren. Dieser Link stammt direkt aus dem Diskussionsforum der Fluentvalidation.

Andere Tipps

Können Sie nicht einfach Ihre eigene Validierungsmethode erstellen, in der Sie die Datenbankvalidierung beginnen würden?

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

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

Ich verwende fluentvalidierung für Datenbankvalidierungen. Geben Sie einfach die Validierungsklasse die Sitzung im CTOR weiter. und machen Sie die Validierung innerhalb der Aktion so etwas wie:

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

Aktualisieren: Basierend auf Ihrem Beispiel füge ich mein Beispiel hinzu ...

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

Zweiter Update:
Wenn Sie darauf bestehen, parameterloser Konstruktor zu verwenden, müssen Sie einige verwenden Inversion des Kontrollbehälters, eine statische Klasse, die so etwas wie die Fabrik Ihrer Objekte ist. Verwenden Sie es so:

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

    }
}

Sie können viele IOC -Behälter finden, am berühmtesten sind Windsor und NinjektSie müssen sich registrieren- den Container einmal anweisen, die gesamte ISSession zu beheben, um das Sitzungsobjekt Ihrer Sitzung zurückzugeben.

Die andere Möglichkeit, wie dies für Sie funktionieren könnte, besteht darin, die Konstruktorinjektion zu verwenden. Diese Methode ist zwar nicht so eindeutig wie die Verwendung einer IOC -Bibliothek, aber es kann helfen, wenn Sie eine statische Möglichkeit haben, auf Ihre Sitzung zuzugreifen oder zu holen.

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

Ich habe ziemlich viel Zeit damit verbracht, genau über das gleiche Problem nachzudenken. Ich verwende Ninject, um mein Repository in meine Web -UI -Ebene zu injizieren, so dass meine Web -Benutzeroberfläche nur über eine Schnittstelle auf die Datenbank zugreift.

Ich möchte in der Lage sein, Dinge zu validieren, die auf die Datenbank zugreifen, z. B. die Überprüfung auf doppelte Namen und daher muss meine Validierung auf das injizierte Repository zugreifen. Ich denke, der beste Weg, dies zu tun, besteht darin, nur die fließende Validierung über die manuelle Methode und nicht über die integrierte MVC -Methode einzurichten. Zum Beispiel:

Erstellen Sie Ihre Validierungsklasse (kann in der Repository -Schnittstelle übergeben):

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;


    }
}

}

Dann können Sie in Ihrem Controller einfach eine Instanz der obigen Klasse erstellen und im Repository übergeben (das Ninjekt hätte in den Controller -Konstruktor injiziert)

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

Beide oben genannten Dateien können im Web -UI -Projekt leben und Sie können dann auch nur die Standard -MVC -Datenalben für die Client -Seitenvalidierung verwenden.

Ich dachte nur, dass ich das für einen Kommentar / helfen würde, jemandem zu helfen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top