Better DI Service Registration with Assembly Scan

Alim Özdemir
3 min readMay 30, 2020

Today, I will talk about a better way to register services for Microsoft’s DI container. Let’s have a look at the standard way of service registration.

There exists three types of object lifetime. I’m not going to explain all of them, since they are already well documented at Microsoft Docs.

For small scale applications the above usage is very acceptable. However, managing a large scale applications might require different solutions.

Now, I will show you 3 different solutions that you might like to use. First, I will consider all lifetimes separately. All three solutions require a NuGet package called Scrutor.

dotnet add package Scrutor

This package allows you to scan assemblies and register the services with implementations.

Solution 1

We will create three different empty interfaces which mark the implementations for lifetime registration.

ITransient, IScoped and ISingleton interfaces will represent each one of the lifetimes. Next thing is Startup.cs file where magic happens.

The following code will scan the current assembly with respect to given lifetime interfaces and register them into DI container.

Solution 2

We can create attributes just like interfaces and use them similar to the first solution.

We can register the attributes with WithAttribute<T> in Startup.cs file.

Now we can use these attributes in the service implementations.

Solution 3

So far, we handled the lifetimes separately. Let’s create a common attribute which contains a lifetime value and then decorate services with that attribute.

This looks better because now we can handle all lifetimes using the ServiceLifetime value provided by Microsoft’s library. Now, in order to scan services, I have created an extension method that iterates through all lifetime types.

Calling the extension method on Startup.cs . You can use either of them.

Run the examples

You can switch the startup settings and run the following controller.

Last solution is my favorite. It uses the ServiceLifetime as a parameter and you don’t need to repeat yourself for every single lifetime.

Assembly

Examples above use FromCallingAssembly at the beginning of each scan, which would register services only in that specific ASP.NET Core Application. If you have separated your services from Application layer into a class library, you might want to use an entry point for that class library. For example, you can create a dummy class ServiceEntryPoint in that library and call FromAssemblyOf<ServiceEntryPoint>() then continue applying the rest of the settings.

Bonus

In order to make things more easier, I would like to draw your attention to the power of reflection. Let’s say you have services that ends with postfix e.g CountryBusinessService , OrderBusinessService , XBusinessService . You can register them however you want, such as the example below.

[ServiceProvider]

Scrutor has an attribute which works similar to the third solution. However, I could not find the documentation about how to use it. Therefore, I will not include it here.

Thanks for reading, you can reach out the source code from here !

--

--