How do you record all validation classes with DryIoc?

3

How can I log all of my validation classes using DryIoc dynamically?

I'm trying the following way down;

using DryIoc;
using FluentValidation;
using System;
using System.Linq;
using System.Reflection;

namespace TesteDryIoC.IU
{
    class Program
    {
        private static Type[] GetTypesInNamespace()
        {
            return Assembly.GetExecutingAssembly().GetTypes().Where(t => String.Equals(t.Namespace, "TesteDryIoC.IU.Validator", StringComparison.Ordinal)).ToArray();
        }
        static void Main(string[] args)
        {

            var container = new Container();

            var implementingClasses =
                Assembly.GetExecutingAssembly() 
                .GetTypes().Where(type => String.Equals(type.Namespace, "TesteDryIoC.IU.Validator", StringComparison.Ordinal) &&
                     type.Name.EndsWith("Validator"));  

            foreach (var implementingClass in implementingClasses)
            {
                    container.Register(implementingClass, Reuse.Singleton);
            }

            Cliente cliente = new Cliente();
            var validador = new ProvaderValidator<Cliente>().GetValidator(container);

            cliente.Nome = "";
            cliente.SobreNome = "Souza";
            cliente.Observacao = "teste";
            cliente.Email = "[email protected]";
            cliente.Idade = 32;
            cliente.DtInclusao = DateTime.Now;
            cliente.Ativo = true;
            cliente.Senha = "";

            var resultad0 = validador.Validate(cliente);

            foreach (var item in resultad0.Errors)
            {
                Console.WriteLine(item.ErrorMessage);
            }
            Console.WriteLine("--------------------------------------");

            Console.ReadKey();
        }
    }
}

My validation classes always end with Validator as shown below.

using FluentValidation;

namespace TesteDryIoC.IU.Validator
{
    class ProdutoValidator : AbstractValidator<Produto>
    {
        public ProdutoValidator()
        {
            RuleFor(x => x.Nome)
               // Garante que a propriedade especificada não seja nula                            
               .NotNull().WithMessage("{PropertyName} deve ser preenchido");
        }
    }
}

Product class;

namespace TesteDryIoC.IU
{
    public class Produto
    {
        public string Nome { get; set; }
    }
}

Generic class to register.

using DryIoc;
using FluentValidation;

namespace TesteDryIoC.IU
{
    public class ProvaderValidator<T> where T : class 
    {
        public IValidator GetValidator(Container container)
        {

            var validador = container.Resolve<IValidator<T>>();
            return validador;
        }
    }
}

The problem here is that when it enters the line var validador = container.Resolve<IValidator<T>>(); it returns the following error;

  

DryIoc.ContainerException: 'Unable to resolve IValidator
  Where no service registrations found and no dynamic registrations   found in 0 Rules.DynamicServiceProviders and nothing in 0   Rules.UnknownServiceResolvers'

The error in more detail;

  

DryIoc.ContainerException occurred HResult = 0x80131509
  Message = Unable to resolve IValidator Where no service   registrations found and no dynamic registrations found in 0   Rules.DynamicServiceProviders and nothing in 0   Rules.UnknownServiceResolvers Source = TestDryIoC.IU StackTrace:
  at DryIoc.Throw.It (Int32 error, Object arg0, Object arg1, Object arg2,   Object arg3) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ DryIcon \ Container.cs: line   11242 at DryIoc.Container.ThrowUnableToResolve (Request request) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ DryIcon \ Container.cs: line   893 at DryIoc.Container.DryIoc.IContainer.ResolveFactory (Request   request) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ DryIcon \ Container.cs: line   851 at DryIoc.Container.ResolveAndCacheDefaultDelegate (Type   serviceType, Boolean ifUnresolvedReturnDefault) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ DryIcon \ Container.cs: line   557 at DryIoc.Container.DryIoc.IResolver.Resolve (Type serviceType,   Boolean ifUnresolvedReturnDefault) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ DryIcon \ Container.cs: line   475 at DryIoc.Resolver.Resolve [TService] (IRresolve Resolve,   IfUnresolved ifUnresolved) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ DryIcon \ Container.cs: line   5665 at TestDryIoC.IU.ProvaderValidator'1.GetValidator (Container   container) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ IProvaderValidator.cs: line   11 at TestDryIoC.IU.Program.Main (String [] args) in   C: \ Work \ SolutionTest \ TestDryIoC \ TestDryIoC.IU \ Program.cs: line 31

    
asked by anonymous 04.07.2017 / 19:28

2 answers

4

It was kind of complicated to solve this problem, it took me a while, but that's the solution I found. First, we created a method like this:

public static void RegisterGeneric<T>(Container container, IValidator<T> validator, IReuse reuse)
{
    container.RegisterDelegate(typeof(IValidator<T>), r => validator, reuse);
}

After discovering all your Validators , within foreach you use reflection to instantiate the class in question and call this new method:

foreach (var implementingClass in implementingClasses)
{
    dynamic validator = Activator.CreateInstance(implementingClass);
    RegisterGeneric(container, validator, Reuse.Singleton);
}

Observations

Since we need to pass an object of type IValidator<T> that is generic, we can not do this:

var validator = (IValidator<T>)Activator.CreateInstance(implementingClass);

And not even that:

IValidator<T> validator = Activator.CreateInstance(implementingClass);

and if we use object , the code does not compile because we can not pass object as argument in a method that expects a generic type (in this case, IValidator<> ). So it was necessary to "abuse" dynamic .

I do not usually use dynamic much, I found it acceptable in this case because you have already ensured that all types found will be implementations of the IValidator<> interface.

    
16.07.2017 / 20:45
0

I found a different way of doing the dependency injection, I was sinning in my foreach.

foreach (var implementingClass in implementingClasses)
{
        container.Register(implementingClass, Reuse.Singleton);
}

It was necessary to retrieve the interface (interfaceValidator) in the loop and make the injection using it.

public static class ContainerRegister
{
    public static Container getContainer()
    {
        Container container = new Container();

        var implementingClasses =
           Assembly.GetExecutingAssembly()
           .GetTypes().Where(type =>
           type.ImplementsServiceType(typeof(IValidator))
           );

        foreach (var implementingClass in implementingClasses)
        {
            var interfaceValidator = implementingClass.GetImplementedInterfaces()[0];
            container.Register(interfaceValidator, implementingClass);
        }

        return container;
    }
}

As I could have more than one class with validation I needed to change how to retrieve the correct class.

public static class ProvadersValidator<T1> where T1 : class
{
    public static IValidator GetValidators(Container container, Func<IEnumerable<IValidator<T1>>, IValidator<T1>> criterio = null)
    {
        var validador = container.Resolve<Lazy<IEnumerable<IValidator<T1>>>>();
        var validadores = validador.Value;
        // TODO: função para selecionar qual usar
        if (criterio != null)
            return criterio(validadores);

        return validadores.First();
    }
}

My call went like this.

var container = ContainerRegister.getContainer();
//
var validadorDefout = ProvadersValidator<Produto>.GetValidators(container);

// buscar a validador especifico por propriedade
var validadorPropriedade = ProvadersValidator<Cliente>.GetValidators(container, (validadores) =>
{
    var validadorEncontrado = validadores.FirstOrDefault(x => x.CreateDescriptor().GetRulesForMember("Observacao").Any());
    return validadorEncontrado ?? validadores.First();
});
    
03.08.2017 / 19:23