On numerous occasions I needed to register all implemented interfaces using the Microsoft dependency injection. Previously, with Autofac, this functionality comes by default.
These are a few extensions that I use to help register generics with Microsoft dependency injection.
Adding multiple generic interfaces
Supposedly we have an IAnimal with multiple implementations of class Cat, Dog and Parrot and we would like to be able to do the following:
services.AddEnumerableInterfaces<IAnimal>(mainAssembly);
The extension for above is simply:
public static void AddEnumerableInterfaces<T>(this IServiceCollection services, Assembly assembly, ServiceLifetime serviceLifeTime = ServiceLifetime.Scoped)
{
var allTypes = assembly
.GetTypes()
.Where(x =>
!x.IsAbstract &&
!x.IsInterface &&
x.GetInterfaces()
.Any(i => i == typeof(T))).ToList();
foreach(var t in allTypes)
{
if(serviceLifeTime == ServiceLifetime.Scoped)
services.TryAddEnumerable(ServiceDescriptor.Scoped(typeof(T), t));
if(serviceLifeTime == ServiceLifetime.Transient)
services.TryAddEnumerable(ServiceDescriptor.Transient(typeof(T), t));
else
services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(T), t));
}
}
Add all implemented interfaces with a class name that ends with a particular word
Supposedly we have multiple implementations of IRepository, with class names such as AnimalRepository, CustomerRepository and so on.
We would like to be able to do:
services.AddImplementedInterfacesNameEndsWith(mainAssembly, “Repository”);
The code for the above is simply like below:
public static void AddImplementedInterfacesNameEndsWith(this IServiceCollection services, Assembly assembly, string endsWith, ServiceLifetime serviceLifeTime = ServiceLifetime.Scoped)
{
var allAssemblies = _getAllReferencedAssemblies(assembly);
var allTypes = allAssemblies
.SelectMany(a => a.GetTypes()
.Where(x =>
!x.IsAbstract &&
!x.IsInterface &&
x.GetInterfaces().Any(i => i.Name.EndsWith(endsWith))))
.ToList();
foreach(var t in allTypes)
{
var interfaceType = t.GetInterfaces().First(i => i.Name.EndsWith(endsWith));
if(serviceLifeTime == ServiceLifetime.Scoped)
services.TryAddEnumerable(ServiceDescriptor.Scoped(interfaceType, t));
if(serviceLifeTime == ServiceLifetime.Transient)
services.TryAddEnumerable(ServiceDescriptor.Transient(interfaceType, t));
else
services.TryAddEnumerable(ServiceDescriptor.Singleton(interfaceType, t));
}
}
In here, the _getAllReferencedAssemblies code is as below:
private static List<Assembly> _getAllReferencedAssemblies(Assembly mainAssembly)
{
var assembliesName = mainAssembly
.GetReferencedAssemblies()
.Where(a => a.Name.Contains("MyApplicationNamespace"))
.ToList();
var loadedAssemblies = assembliesName.Select(a => Assembly.Load(a)).ToList();
loadedAssemblies.Add(mainAssembly);
return loadedAssemblies.ToList();
}
The _getAllReferencedAssemblies above helps to ensure when we register the interface above, we include all of the assemblies require, as well as ensuring that all of the assemblies had been loaded during runtime.