While answering this question on SO I couldn't figure out the best technique for registering many implementations of a generic type with an instance of LifetimeScopeLifestyle
within SimpleInjector.
The recommended method for this form of registration is something like this:
container.RegisterManyForOpenGeneric(typeof(IRepository<>),
typeof(IRepository<>).Assembly);
But this does not allow an instance of LifetimeScopeLifestyle
to be passed in.
Below is what I came up with but I know it's not resilient enough as it is checking for any generic interface, not specifically IRepository<>
. Can anyone tell me how to do this?
public static void Configure(Container container)
{
var lifetimeScope = new LifetimeScopeLifestyle();
container.Register<IUnitOfWork, UnitOfWork>(lifetimeScope);
//this query needs improvement
var registrations =
from type in typeof(IRepository<>).Assembly.GetExportedTypes()
where typeof(IRepository).IsAssignableFrom(type)
&& type.IsClass
&& !type.IsAbstract
from service in type.GetInterfaces()
where service.IsGenericType
select new { Service = service, Implementation = type };
foreach (var registration in registrations)
{
container.Register(registration.Service,
registration.Implementation, lifetimeScope);
}
}
TLDR:
container.RegisterManyForOpenGeneric(
typeof(IRepository<>),
lifetimeScope,
typeof(IRepository<>).Assembly);
First of all, your query is wrong. It should have been:
var registrations =
from type in
typeof(IRepository<>).Assembly.GetExportedTypes()
where !service.IsAbstract
where !service.IsGenericTypeDefinition
from @interface in type.GetInterfaces()
where @interface.IsGenericType
where @interface.GetGenericTypeDefinition() ==
typeof(IRepository<>)
select new { Service = @interface, Impl = type };
Second, the framework contains a GetTypesToRegister
method to fetch these types for you, which excludes decorator types:
var repositoryTypes =
OpenGenericBatchRegistrationExtensions.GetTypesToRegister(
container, typeof(IRepository<>),
typeof(IRepository<>).Assembly);
var registrations =
from type in repositoryTypes
from @interface in type.GetInterfaces()
where @interface.IsGenericType
where @interface.GetGenericTypeDefinition() ==
typeof(IRepository<>)
select new { Service = @interface, Impl = type };
But it gets better, the container contains an overload of the RegisterManyForOpenGeneric
method that takes a callback delegate that allows you to do the registration as follows:
container.RegisterManyForOpenGeneric(
typeof(IRepository<>),
(service, impls) =>
{
container.Register(service, impls.Single(),
lifetimeScope);
},
typeof(IRepository<>).Assembly);
But most importantly, the framework contains RegisterManyForOpenGeneric
overloads that takes in an Lifetime
. So you are able to simplify your registration to the following:
container.RegisterManyForOpenGeneric(
typeof(IRepository<>),
lifetimeScope,
typeof(IRepository<>).Assembly);