As application business logic get more and more complex we as developers need to develop more and more services and repositories in order to use them to implement the business logic model. and of course we need to register these repositories and services in our app Dependency injection container in order to inject them anywhere in our application.
The Ordinary way for registering repositories and services, is by using the program.cs class and add these services one by one, which is in fact is not a good idea, and not even practical, as this class will contain more and more repeated registering of different classes, and the class will get more noisy by time.
The idea I’m trying to clarify here, is how about if we can register all our application services/repositories with only one line like:
builder.Services.RegisterAppServices();
In order to do, we have to write a very simple extension method that will use reflection to get all our services or repositories interfaces with their implementation classes and register them automatically in the DI container. we need al so to make sure that all the services interfaces are inheriting from a specific interface, in the example below all my interfaces inherit from IService
interface
public static class ServicesInstallerExtension
{
public static void RegisterAppServices(this IServiceCollection serviceDescriptors)
{
Assembly assembly = typeof(IService).Assembly;
Type[] assemblyTypes = assembly.GetTypes();
IEnumerable<Type> interfaces = assemblyTypes.Where(t => t.IsInterface && typeof(IService).IsAssignableFrom(t) && t != typeof(IService));
foreach (var interfaceType in interfaces)
{
// find types that implement this interface
var implementations = assemblyTypes.Where(t => !t.IsInterface && interfaceType.IsAssignableFrom(t));
// register interface with implementations
foreach (var implementation in implementations)
serviceDescriptors.AddScoped(interfaceType, implementation);
}
}
}
As you can see from code above all the services are registered as scoped services.
We can modify a little bit the code above in a way that allow us to automatically register services as Singlton/Scoped/Transient by using a different Base interface for each service. so lets say that we have three different base interfaces
- IScopedService : To be inherited from Interfaces that need to be registered as Scoped servbices
- ISingltonService : To be inherited from Interfaces that need to be registered as Singlton services
- ITransientServiec: To be inherited from Interfaces that need to be registered as Transient services
Now all interfaces that inherit from IScopedService will be registered as scoped services , interfaces that inherit from ISingltonService will be registered as Singlton service. and interfaces that inherit from ITransientService will be registerd as Transient services in the dependency container of our app.
With that said our final extension method will look something like this:
public static class ServicesInstallerExtension
{
public static void RegisterAppServices(this IServiceCollection serviceDescriptors)
{
Assembly assembly = typeof(IScopedService).Assembly;
Type[] assemblyTypes = assembly.GetTypes();
Type[] scopeTypes = new Type[] { typeof(ISingltonService), typeof(IScopedService), typeof(ITransientService) };
foreach (var scopeType in scopeTypes)
RegisterScopedService(serviceDescriptors, assemblyTypes, scopeType);
}
private static void RegisterScopedService(IServiceCollection serviceDescriptors, Type[] assemblyTypes, Type scopeInterfaceType)
{
// find all interfaces that inherit from this scope interface
IEnumerable<Type> interfaces = assemblyTypes.Where(t => t.IsInterface && scopeInterfaceType.IsAssignableFrom(t) && t != scopeInterfaceType);
foreach (var interfaceType in interfaces)
{
// find types that implement this interface
var implementations = assemblyTypes.Where(t => !t.IsInterface && interfaceType.IsAssignableFrom(t));
// register interface with its implementations
foreach (var implementation in implementations)
RegisterService(serviceDescriptors, interfaceType, implementation, scopeInterfaceType);
}
}
private static void RegisterService(IServiceCollection serviceDescriptors, Type interace, Type implementation, Type scopeInterfaceType)
{
switch (scopeInterfaceType.Name)
{
case nameof(ISingltonService):
serviceDescriptors.AddSingleton(interace, implementation);
break;
case nameof(IScopedService):
serviceDescriptors.AddScoped(interace, implementation);
break;
case nameof(ITransientService):
serviceDescriptors.AddTransient(interace, implementation);
break;
}
}
}
And that’s it, hope you like this tutorial, and see you next time.