Simple Service Collection Extensions For Microsoft Dependency Injection

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s