DEV Community

Cover image for Scrutor, automatic dependency injection for ASP.NET Core
Stephany Henrique A
Stephany Henrique A

Posted on

Scrutor, automatic dependency injection for ASP.NET Core

If you set up the dependency injection container by hand, you need to know this library for .Net Core. With this lib, you get free to take care of what is important.

Do not you know about dependency injection? Here you will find an explanation about this technique https://en.wikipedia.org/wiki/Dependency_injection. Please, stop a moment and try to learn about this important concept.

Hi guys! Today I write a fast article about .Net Core, I will explain about Scrutor. This is a nice lib that configures our classes to the dependency injection container. When I work with .Net Core and I need to inject a service (class) at a controller or another class I must configure each service that I need. This instruction is done at ConfigureServices method. So here is going an example.

services.AddScoped<SolicitadorDeManutencao, SolicitadorDeManutencao>();
services.AddScoped<FabricaDeSolicitacaoDeManutencao, FabricaDeSolicitacaoDeManutencao>();
services.AddScoped<AnaliseDeAprovacaoDaSolicitacaoDeManutencao, AnaliseDeAprovacaoDaSolicitacaoDeManutencao>();

The ConfigureServices method is responsible for configuring all services of my project, there I configure EF Core, Identity, MVC Controller. The .Net Core uses this configuration to know all services that are necessary and to instance this services when requested. If I do not configure, the services will not work.

As you see above, each class was configured to be injected when needed. Therefore if a controller will use one of the above classes, the .Net Core knows how to inject because it was configured as a service.

This method tends to be very large, imagine a project that has 30 services, you will configure the 30 services. I do not like this, because other frameworks like Spring Boot I do not need to make this configuration, I just decorate the class as [Service]. The good thing, with Scrutor this is over.

If you desire to learn more about Scrutor, please, access https://github.com/khellang/Scrutor.

To configure Scrutor in my project, I need two steps

  1. Add package
  2. Configure lib in method Configure Service

Let's start.

I like to use .Net CLI, so I write in a terminal

dotnet add package Scrutor

Ok, now in ConfigureServices method in the Startup class, let's write some code

services.Scan(sc =>
{
    sc.FromCallingAssembly()
        .FromAssemblies(typeof(Program).Assembly)
        .AddClasses()
        .AsSelf();
});

A fast explanation, when I use o service Scan, I'm configuring all classes to be working as a service. See that I'm using the "Program" class as a reference to my library, where are my other classes. I can input any class of this library.

I'm configuring all classes from this library (where the Program class is). Normally I do not like to add all classes to be configured, for example, I do not need to configure Entities or Values Object, because these classes do not need. Then I have a trick.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ServiceAttribute : Attribute
{

}

I can create a class attribute to decorate all classes that are services. For example.

[Service]
public class ConfirmacaoDeUsuario
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly ApplicationDbContext _context;
        ...

Now, I can change my code where I use Scrutor to configure only classes with the attribute of type Service.

services.Scan(scan => scan
    .FromAssemblyOf<Program>()
        .AddClasses(@class => @class.WithAttribute<ServiceAttribute>())
        .UsingRegistrationStrategy(RegistrationStrategy.Skip)
        .AsSelf()
);

Now, I am using also the option called "UsingRegistrationStrategy", this means to not configure a class more than once.

Guys, I hope that you have liked and I see you next time.

Top comments (1)

Collapse
 
gregoryagu profile image
Greg Gum

Great article on Scutor! I implemented as suggested, then added an Attribute called InjectAsScoped and then updated by scan code to scan for that attribute and set the lifetime to scoped.