Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

.Net Core DI, How to register all existing assignable types in an assembly

5.00/5 (2 votes)
13 Jan 2020CPOL2 min read 20.8K  
In this article, we'll explain how to register (Add) all specific interface assignable types in an assembly and will use them in a class.

Introduction

.Net Core came with its own Dependency Injection container and .Net Core 3.0 has shown that the .Net Core DI can be reliable and efficient. It still has some shortcomings. There are many extensions to fix these shortcomings that provide excellent opportunities. Basically, .Net core has made it easy to write and extend it. 

In this article, I will show you how to add a new extension to register all assignable types to a specific interface (Class: Interface). 
This will be helpful if you have different logics for a task and want to store them in different classes and load them by configuration.

Background

Let's say you have a specific logic to calculate employees' tax and you have several types of employees and each employee type has its own logic. So, you will have an interface and each employee type should implement the interface. Users should have this feature to add a new employee type, which means the user needs to add new logic for the new employee type too. So, base one Open-Close principle we don't want to open the main code for changes but we need to make a way for the user to add the new logic. So, we add an interface layer and a project to add new classes. When the user adds a new logic, he should restart the app the DI will load all classes in that project which implements that interfaces. Here, our nice extension will play its role.

Using the code

As you can see the extension is really simple and easy but it is doing magic ;)

C#
public static class RegisterAllAssignableTypes
{
   public static void RegisterAllAssignableType<T>(this IServiceCollection services, string assemblyName)
   {
      var assembly = AppDomain.CurrentDomain.Load(assemblyName);
      var types = assembly.GetTypes().Where(p => typeof(T).IsAssignableFrom(p)).ToArray();

       var addTransientMethod = typeof(ServiceCollectionServiceExtensions).GetMethods().FirstOrDefault(m =>
           m.Name == "AddTransient" &&
           m.IsGenericMethod == true &&
           m.GetGenericArguments().Count() == 2);

       foreach (var type in types)
       {
          if (type.IsInterface)
             continue;

          var method = addTransientMethod.MakeGenericMethod(new[] { typeof(T), type });
          method.Invoke(services, new[] { services });
       }
   }

   public static Interface ResolveByName<Interface>(this IServiceProvider serviceProvider, string typeName)
   {
      var allRegisteredTypes = serviceProvider.GetRequiredService<IEnumerable<Interface>>();
      var resolvedService = allRegisteredTypes.FirstOrDefault(p => p.GetType().FullName.Contains(typeName));

      if (resolvedService != null)
      {
         return resolvedService;
      }
      else
      {
         throw new TypeNotFound($"{typeName} type not found.");
      }
   }
}

 

The first method, RegisterAllAssignableTypes will be used when you are configuring the Dot Net core DI. So you will have a line like this:

C#
services.RegisterAllAssignableType<ITaxCalculator><itaxcalculation>("MyApp.ExtendedLogics");

And it will read all the classes in the MyApp.Extended project which implements ITaxCalculator and registers them as Transient in DI container. 

So, in the consumer class, you just need to add IServiceProvider to the constructor.

C#
public class EmployeeProcess
{
    private readonly IServiceProvider _serviceProvider;

    public(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
}

Now, when you load an employee from the database and know its type you can easily load its tax calculation logic by this extension method

C#
    var employeeType = employee.Type;
    var employeeTaxLogic = _serviceProvider.ResolveByName<itaxcalculator>(employeeType);
    
    var tax = employeeTaxLogic.CalculateTax(employee);
</itaxcalculator>

Points of Interest

I've learned more about .Net Core DI which seems that will be a new generation in .Net applications.

History

You can access this code NuGet:  MOME.DotNetDIExtensions

I would be happy if you use it and report its issue and recommend your ideas about how we can improve it and which DI extension you need. So, I can add them to this package and develop and improve it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)