Question

I'm trying to automate registration of AutoMapper profiles with Ninject. For this I need to instantiate objects of types that inherit from AutoMapper.Profile, for example:

public class WordMapping : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Datacontext.Entities.Word, Domain.Entities.Word>();
        Mapper.CreateMap<Domain.Entities.Word, Datacontext.Entities.Word>();
    }
}

First I tried to do this only by means of reflection and it worked like a charm:

var profileType = typeof(AutoMapper.Profile);

var profiles = AppDomain.CurrentDomain.GetAssemblies()
                        .SelectMany(a => a.GetTypes())
                        .Where(t => profileType.IsAssignableFrom(t) && t.GetConstructor(Type.EmptyTypes) != null)
                        .Select(Activator.CreateInstance)
                        .Cast<Profile>();

foreach (var profile in profiles)
{
    Mapper.AddProfile(profile);
}

But when I try to do the same thing with Ninject:

public class MappingModules : NinjectModule
{
    public override void Load()
    {
        Kernel.Bind(scanner =>
        {
            scanner.FromAssembliesMatching("*")
                .SelectAllClasses()
                .InheritedFrom<AutoMapper.Profile>();
        });

        var profiles = Kernel.GetAll<Profile>();
        foreach (var profile in profiles)
        {
            Mapper.AddProfile(profile);
        }
    }
}

I get the error:

SetUp : Ninject.ActivationException : Error activating Profile using implicit self-binding of Profile No constructor was available to create an instance of the implementation type.

Activation path: 1) Request for Profile

Suggestions: 1) Ensure that the implementation type has a public constructor. 2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.

I suspect that this happens because of Ninject trying to instantiate Mapper.Profile itself but it doesn't have a public constructor. But when I change .InheritedFrom<AutoMapper.Profile>() to .Where(p => p.IsAssignableFrom(typeof(AutoMapper.Profile)) && p != typeof(AutoMapper.Profile)) it doesn't help either.

It's worth to mention that Ninject's composition root, Ninject' modules and classes inherited from AutoMapper.Profile are located in 3 different assemblies.

Help me please to figure out what I am missing.

Était-ce utile?

La solution

Your convention based binding is missing.... the binding! Add a .BindBase() to the end of the conditional binding.

    Kernel.Bind(scanner =>
    {
        scanner.FromAssembliesMatching("*")
            .SelectAllClasses()
            .InheritedFrom<AutoMapper.Profile>()
            .BindBase();
    });

BindBase() will bind the class to it's immediate base class, which in your example (WordMapping : Profile) is Profile. If your inheritance hierarchy would be WordMapping : MyMapping : Profile it would bind to MyMapping (which would not be okay for you). So if you need it to be bound to a different type, have a look at https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top