How do you register all validation classes with Dryioc?

Asked

Viewed 150 times

3

How can I log all my validation classes using Dryioc dynamically ?

I’m trying this 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 you get in 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 with more details;

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=Testedryioc.IU Stacktrace:
At Dryioc.Throw.It(Int32 error, Object arg0, Object arg1, Object arg2, Object Arg3) in C: Work Solutiontest Testedryioc Testedryioc.IU Dryioc Container.Cs:line 11242 at Dryioc.Container.Throwunabletoresolve(Request request) in C: Work Solutiontest Testedryioc Testedryioc.IU Dryioc Container.Cs:line 893 at Dryioc.Container.Dryioc.IContainer.Resolvefactory(Request request) in C: Work Solutiontest Testedryioc Testedryioc.IU Dryioc Container.Cs:line 851 at Dryioc.Container.Resolveandcachedefaultdelegate(Type serviceType, Boolean ifUnresolvedReturnDefault) in C: Work Solutiontest Testedryioc Testedryioc.IU Dryioc Container.Cs:line 557 at Dryioc.Container.Dryioc.IResolver.Resolve(Type serviceType, Boolean ifUnresolvedReturnDefault) in C: Work Solutiontest Testedryioc Testedryioc.IU Dryioc Container.Cs:line 475 at Dryioc.Resolver.Resolve[Tservice](Iresolver resolve, Ifunresolved ifUnresolved) in C: Work Solutiontest Testedryioc Testedryioc.IU Dryioc Container.Cs:line 5665 at Testedryioc.IU.Provadervalidator`1.Getvalidator(Container container) in C: Work Solutiontest Testedryioc Testedryioc.IU Iprovadervalidator.Cs:line 11 at Testedryioc.IU.Program.Main(String[] args) in C: Work Solutiontest Testedryioc Testedryioc.IU Program.Cs:line 31

2 answers

4


It was kind of complicated to solve this problem, it took me a long time, but here’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 his Validators, within the 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);
}

Remarks

How we need to pass an object of the type IValidator<T> which is generic, we can’t do that:

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

and neither does that:

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

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

I don’t usually use much dynamic, found acceptable in this case because you have already ensured that all types found will be interface implementations IValidator<>.

  • Vlw, nice that managed to find a solution, if dealing with dryioc is a little unexplored thing yet, I found a way to do this a little bit differently. If something does not appear better I signal your answer at the end of the reward.

  • 1

    @Marconciliosouza thank you! I didn’t know it myself, I installed it here to do the tests, but this question of registering several classes of a given interface dynamically is something we always end up using in dependency injection frameworks. I’ll keep thinking here and anything else I edit my answer with a second alternative.

  • posted the way I did.

0

I found a different way to do the dependency injection, was sinning on my foreach.

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

It was necessary to recover 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 the way to recover 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();
});

Browser other questions tagged

You are not signed in. Login or sign up in order to post.