Reputation: 5398
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.
Upvotes: 2
Views: 363
Reputation: 13243
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
Upvotes: 5