Свободная проверка в ASP.net MVC - Проверка базы данных - PullRequest
4 голосов
/ 29 ноября 2011

Я использую инфраструктуру Fluent Validation в моем проекте ASP.net MVC 3. До сих пор все мои проверки были очень простыми (убедитесь, что строка не пустая, только определенной длины и т. Д.), Но теперь мне нужно проверить, существует ли что-то в базе данных или нет.

  1. Следует ли в этом случае использовать Fluid 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();

Проблема в том, что теперь у меня есть валидатор, который должен взаимодействовать с моей базой данных, используя репозиторий, но, поскольку я не создаю валидаторы, я не знаю, как я получу эту зависимость, кроме жесткого кодирования тип бетона.

Ответы [ 5 ]

1 голос
/ 08 декабря 2011

Эта ссылка может помочь вам реализовать то, что вы ищете, без необходимости вручную создавать и проверять ваши модели. Эта ссылка непосредственно с дискуссионного форума FluentValidation.

0 голосов
/ 02 мая 2013

Я потратил довольно много времени на размышления об этой же проблеме.Я использую ninject, чтобы внедрить мой репозиторий в слой своего веб-интерфейса, чтобы мой веб-интерфейс осуществлял доступ к базе данных только через интерфейс.

Я хочу иметь возможность проверять вещи, которые обращаются к базе данных, например проверять наличие дубликатов.имена и, следовательно, моя проверка должна получить доступ к введенному хранилищу.Я думаю, что лучший способ сделать это - просто настроить 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;


    }
}

}

Тогда в вашем контроллере вы можете просто создать экземпляр вышеупомянутого классаи передайте в хранилище (этот объект мог бы быть вставлен в конструктор контроллера)

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

Оба вышеупомянутых файла могут жить в проекте веб-интерфейса, и тогда вы также можете просто использовать стандартные MVC DataAnnotations на стороне клиентавалидация.

Просто подумал, что я выложу это для комментариев / помощи кому-то.

0 голосов
/ 09 декабря 2011

Другой способ, которым это может работать для вас, - использование инжектора Constructor. Хотя этот метод не так прост, как использование библиотеки 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 голосов
/ 08 декабря 2011

Разве вы не можете просто создать свой собственный метод проверки, при котором вы бы начали проверку базы данных?

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

    private static bool BeInDatabase(string name)
    {
        // Do database validation and return false if not valid
        return false;
    }
0 голосов
/ 30 ноября 2011

Я использую 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");
}

Второе обновление:
Если вы настаиваете на использовании конструктора без параметров, вам придется использовать некоторый Контейнер инверсии , статический класс, похожий на 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, наиболее известные из них Windsor и Ninject , Вам нужно будет зарегистрироваться - дать указание контейнеру один раз разрешить все сеансы IS для возврата объекта сеанса.

...