Scrutor: Enhancing Dependency Injection in .NET Core
Scrutor is a lightweight library for .NET Core that enhances dependency injection (DI) by enabling automated assembly scanning and registration of services. With Scrutor, you can reduce manual configuration by automatically discovering and registering services based on conventions or attributes.
How It Works
Scrutor builds on top of .NET Core’s built-in Dependency Injection (DI) framework. It simplifies service registration by:
- Scanning Assemblies: It scans through your project’s assemblies for classes or interfaces that match certain patterns or conventions.
- Auto-Registering Services: It automatically registers discovered classes with the DI container, specifying their lifetimes (e.g., Transient, Scoped, or Singleton).
- Applying Filters: You can use predicates to include or exclude specific types during registration.
How to Set It Up
1. Install Scrutor
Add the NuGet package to your project:
dotnet add package Scrutor
2. Set Up in Program.cs
or Startup.cs
- Example of Basic Registration:
using Microsoft.Extensions.DependencyInjection;
using Scrutor;
var builder = WebApplication.CreateBuilder(args);
builder.Services.Scan(scan => scan
.FromAssemblyOf<Program>() // Scans the current assembly
.AddClasses() // Finds all classes
.AsImplementedInterfaces() // Registers them as their implemented interfaces
.WithScopedLifetime()); // Sets the lifetime to Scoped
var app = builder.Build();
app.Run();
This snippet scans for all classes in the current assembly, registers them as their implemented interfaces, and sets their lifetime to Scoped.
3. Apply Filters (Optional)
You can fine-tune what gets registered:
builder.Services.Scan(scan => scan
.FromAssemblyOf<Program>()
.AddClasses(classes => classes.Where(type => type.Name.EndsWith("Service")))
.AsImplementedInterfaces()
.WithSingletonLifetime());
In this case, only classes ending with “Service” are registered, with a Singleton lifetime.
4. Exclude Specific Types
For more control, exclude classes:
builder.Services.Scan(scan => scan
.FromAssemblyOf<Program>()
.AddClasses(classes => classes.Except<SomeSpecificService>())
.AsSelf()
.WithTransientLifetime());
This excludes the SomeSpecificService
class while registering everything else.
Example Use Case
Imagine you have the following services in your application:
public interface IOrderService { /* Methods */ }
public class OrderService : IOrderService { /* Implementation */ }
public interface IUserService { /* Methods */ }
public class UserService : IUserService { /* Implementation */ }
With Scrutor, you can avoid manually registering each service:
builder.Services.Scan(scan => scan
.FromAssemblyOf<Program>()
.AddClasses()
.AsImplementedInterfaces()
.WithScopedLifetime());
Scrutor will automatically detect OrderService
and UserService
, register them as IOrderService
and IUserService
respectively, and set their lifetimes to Scoped.
Why Use Scrutor?
- Saves Time: No need to manually list every service in your
Program.cs
orStartup.cs
. - Flexible: You can easily add filters and conditions.
- Scalable: Great for large projects with many services.
This guide introduces the basics of Scrutor and highlights how it enhances dependency injection in .NET Core projects.