FluentValidation 验证工厂和 Ninject DI 容器

发布于 2024-12-28 18:56:24 字数 2634 浏览 4 评论 0 原文

我正在使用 NinjectHttpApplication 以及我的项目中定义的几个模块。

我想要的是创建 FluentValidation 验证工厂,如 http://www.thekip.nl/2011/09/22/using-fluidation-for-both-domain-validation-and-validation-in-mvc-projects/

要创建一个具体的验证工厂,我需要重写

IValidator CreateInstance(Type validatorType) 

我应该调用的方法

return kernel.Get<validatorType>() as IValidator

,但我读到不建议在 Global.asax 范围之外使用 IKernel。

有哪些选择可以实现我想要的效果?

编辑:使用 Ninject-FluentValidation 扩展

正如 Remo 所说,GitHub 上有一个扩展(https://github.com/ninject/ninject.web.mvc. Fluidvalidation)。扩展中有一个类:

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

可以。我不知道是否可以更好地解决它。另外,我不明白需要将 IKernel 公开为 NinjectValidationFactory 上的公共属性。

I'm using NinjectHttpApplication with couple modules defined in my project.

What I want is to create FluentValidation validation factory as described in http://www.thekip.nl/2011/09/22/using-fluentvalidation-for-both-domain-validation-and-validation-in-mvc-projects/.

To create a concrete validation factory I need to override

IValidator CreateInstance(Type validatorType) 

method where I should then call

return kernel.Get<validatorType>() as IValidator

But I've read that using IKernel outside of Global.asax scope is not recommended.

What options are there to make what I want?

EDIT: using Ninject-FluentValidation extension

As Remo's stated there's an extension on GitHub (https://github.com/ninject/ninject.web.mvc.fluentvalidation). There's a class in the extension:

public class NinjectValidatorFactory : ValidatorFactoryBase { ... }

which takes IKernel in constructor and creates instances of IValidator

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

    return Kernel.Get(validatorType) as IValidator;
}

then my code goes like:

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

That works. I don't know could it be resolved better though. Also I don't understand the need to expose IKernel as a public property on NinjectValidationFactory.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心欲静而疯不止 2025-01-04 18:56:25

Ninject.Web.Mvc.FluentValidation 扩展向 Ninject 添加了对流畅验证的支持。可以在 NuGet 上找到它。请参阅https://github.com/ninject/ninject.web.mvc.fluidation

The Ninject.Web.Mvc.FluentValidation extension adds support for fluent validation to Ninject. It can be found on NuGet. See https://github.com/ninject/ninject.web.mvc.fluentvalidation

秋叶绚丽 2025-01-04 18:56:25

强烈建议阅读 Mark Seemann 的.NET 中的依赖注入< /a> 书。

为了简单起见,如果您希望向容器请求依赖项,则您没有使用依赖项注入。你不调用容器。它会打电话给你。

I highly advise reading Mark Seemann's Dependency Injection in .NET book.

To keep it simple, if you're looking to ask the container for a dependency, you're not using Dependency Injection. You don't call the container. It'll call you.

橘味果▽酱 2025-01-04 18:56:25

这很简单。我向您展示一个简单的控制台应用程序来演示使用 NInject 进行 FluentValidation。

  1. 在 Visual Studio 中创建控制台应用程序。
  2. 安装所有 nuget 包 FluentValidation 和 NInject。

Install-Package NInject

Install-Package FluentValidation

  1. 创建以下类。

    公共类客户
    {
        公共 int Id { 得到;放; }
        公共字符串姓氏{获取;放; }
        公共字符串名字{获取;放; }
        公共小数折扣 { get;放; }
        公共字符串地址{获取;放; }
    }
    
    使用 FluentValidation;
    公共类 CustomerValidator : AbstractValidator;
    {
        公共客户验证器()
        {
            //RuleFor(customer => customer.Surname).NotNull();
            RuleFor(customer => customer.Surname).NotNull().NotEqual("foo");
        }
    }
    
    使用 FluentValidation;
    使用 Ninject;
    使用系统;
    
    公共类 NInjectValidatorFactory : ValidatorFactoryBase
    {
        私有只读 IKernel m_NInjectKernel;
        公共 NInjectValidatorFactory(IKernel 内核)
        {
            如果(内核==空)
                throw new ArgumentNullException("NInject 内核注入为空!!");
    
            m_NInjectKernel = 内核;
        }
        公共覆盖 IValidator CreateInstance(类型 validatorType)
        {
            返回 m_NInjectKernel.Get(validatorType) 作为 IValidator;
        }
    }
    

    4.程序类中的main方法如下。

    使用 FluentValidation;
    使用 Ninject;
    使用系统;
    使用 System.Linq;
    
    班级计划
    {
        静态无效主(字符串[]参数)
        {
            // 设置 DI 容器。
            var kernel = new StandardKernel();
            kernel.Bind>().To().InSingletonScope();
    
            var nInjectvalidationFactory = kernel.Get();
            var customer = kernel.Get();
    
            var customerValidator = nInjectvalidationFactory.GetValidator();
    
            var 结果 = 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();
        }
    }
    
  2. 运行这个即可。该代码非常不言自明。在 main 方法中,我们正在设置 DI 容器,在本例中为 NInject。然后我们进行必要的绑定(映射)。请注意,仅需要一个映射。正如解释的那样,这也是一个单例 此处用于性能。

This is pretty simple. I show you a simple console app to demonstrate FluentValidation with NInject.

  1. Create a console app in visual studio.
  2. Intsall the nuget packages FluentValidation and NInject.

Install-Package NInject

Install-Package FluentValidation

  1. Create the following classes.

    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.The main method inside the program class would be as follows.

    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();
        }
    }
    
    1. Just run this. The code is pretty self explanatory. Inside the main method, we are setting up the DI container, NInject in this case. Then we are doing the necessary bindings(mappings). Note only one mapping is required. That too as a singleton as explained here for performance.
ゃ人海孤独症 2025-01-04 18:56:25

根据您的内核实现,这本身不是问题。

不建议这样做,因为它会创建对内核的依赖关系(因此您使用的是服务位置而不是依赖注入)。

另一种选择是使用 Ninjects 提供者概念,如 所描述亚历山大·贝列茨基

Depending on your implementation of the kernel, this is not a problem as such.

It is not recommended, as it creates a dependency on the kernel (and as such you are using Service Location and not Dependency Injection).

Another option would be to use Ninjects notion of Providers as described by Alexsander Beletsky.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文