Фабрика проверки FluentValidation и контейнер Ninject DI - PullRequest
4 голосов
/ 25 января 2012

Я использую NinjectHttpApplication с парой модулей, определенных в моем проекте.

Я хочу создать FluentValidation фабрику проверки, как описано в http://www.thekip.nl/2011/09/22/using-fluentvalidation-for-both-domain-validation-and-validation-in-mvc-projects/.

Чтобы создать конкретную фабрику проверки, мне нужно переопределить

IValidator CreateInstance(Type validatorType) 

метод, в котором я должен затем вызывать

return kernel.Get<validatorType>() as IValidator

Но я читал, что использование IKernel за пределами Global.asax не рекомендуется.

Какие есть варианты, чтобы сделать то, что я хочу?

РЕДАКТИРОВАТЬ: используя расширение Ninject-FluentValidation

Как указано в Remo, есть расширение на GitHub (https://github.com/ninject/ninject.web.mvc.fluentvalidation). В этом расширении есть класс:

public class NinjectValidatorFactory : ValidatorFactoryBase { ... }

, который принимает IKernel в конструкторе и создает экземпляры IValidator

public override IValidator CreateInstance(Type validatorType)
{
    if(((IList<IBinding>)Kernel.GetBindings(validatorType)).Count == 0)
    {
        return null;
    }

    return Kernel.Get(validatorType) as IValidator;
}

, тогда мой код выглядит так:

public class MvcApplication : NinjectHttpApplication
{
    private NinjectValidatorFactory nvfactory;

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());                        
    }
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Employee", action = "Index", id = UrlParameter.Optional }
        );
    }        
    protected override void OnApplicationStarted()
    {
        AreaRegistration.RegisterAllAreas();
        RegisterRoutes(RouteTable.Routes);

        ModelValidatorProviders.Providers.Clear();
        ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(nvfactory));            
    }
    protected override IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Load(Assembly.GetExecutingAssembly());            
        nvfactory = new NinjectValidatorFactory(kernel);

        return kernel;
    }
}

Это работает. Iне знаю, может ли это быть решено лучше, хотя я также не понимаю необходимости выставлять IKernel как публичную собственность на NinjectValidationFactory.

Ответы [ 4 ]

10 голосов
/ 01 февраля 2012

Расширение Ninject.Web.Mvc.FluentValidation добавляет поддержку быстрой проверки в Ninject.Его можно найти на NuGet.Смотри https://github.com/ninject/ninject.web.mvc.fluentvalidation

4 голосов
/ 16 декабря 2012

I очень советую прочесть книгу Маркса Симанна в .NET book.

Для простоты, если вы ищетечтобы запросить у контейнера зависимость, вы не используете Dependency Injection.Вы не вызываете контейнер.Он тебе позвонит.

1 голос
/ 29 июня 2017

Это довольно просто.Я покажу вам простое консольное приложение для демонстрации FluentValidation с помощью NInject.

  1. Создайте консольное приложение в visual studio.
  2. Intsall пакеты nuget FluentValidation и NInject.

Install-Package NInject

Install-Package FluentValidation

Создайте следующие классы.

public class Customer
{
    public int Id { get; set; }
    public string Surname { get; set; }
    public string Forename { get; set; }
    public decimal Discount { get; set; }
    public string Address { get; set; }
}

using FluentValidation;
public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        //RuleFor(customer => customer.Surname).NotNull();
        RuleFor(customer => customer.Surname).NotNull().NotEqual("foo");
    }
}

using FluentValidation;
using Ninject;
using System;

public class NInjectValidatorFactory : ValidatorFactoryBase
{
    private readonly IKernel m_NInjectKernel;
    public NInjectValidatorFactory(IKernel kernel)
    {
        if (kernel == null)
            throw new ArgumentNullException("NInject kernel injected is null!!");

        m_NInjectKernel = kernel;
    }
    public override IValidator CreateInstance(Type validatorType)
    {
        return m_NInjectKernel.Get(validatorType) as IValidator;
    }
}

4. Основной метод внутри класса программы будет следующим:

using FluentValidation;
using Ninject;
using System;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        // Set up the DI Container.
        var kernel = new StandardKernel();
        kernel.Bind<IValidator<Customer>>().To<CustomerValidator>().InSingletonScope();

        var nInjectvalidationFactory = kernel.Get<NInjectValidatorFactory>();
        var customer = kernel.Get<Customer>();

        var customerValidator = nInjectvalidationFactory.GetValidator<Customer>();

        var results = customerValidator.Validate(customer);

        if (!results.IsValid)
            results.Errors.ToList().ForEach(e =>
            {
                Console.WriteLine(e.ErrorMessage);
                Console.WriteLine(e.ErrorCode);
                Console.WriteLine(e.PropertyName);
                Console.WriteLine(e.ResourceName);
                Console.WriteLine(e.Severity);
            }
            );
        Console.ReadLine();
    }
}
Просто запустите это.Код довольно понятен.Внутри основного метода мы настраиваем контейнер DI, в данном случае NInject.Затем мы делаем необходимые привязки (отображения).Обратите внимание, что требуется только одно сопоставление.Это тоже как синглтон, как объяснено здесь для производительности.
0 голосов
/ 25 января 2012

В зависимости от вашей реализации ядра, это не является проблемой как таковой.

Это не рекомендуется, так как это создает зависимость от ядра (и поэтому вы используете расположение службы, а не зависимость).Инъекция).

Другим вариантом было бы использование понятия провайдеров Ninjects, как описано Александр Белецкий .

...