
1. Introduction
Dependency Injection (DI) is a foundational concept in .NET and ASP.NET Core. The built-in DI container is:
Fast
Simple
Perfectly adequate for small applications
However, as applications scale—especially when adopting:
Clean Architecture
Minimal APIs
Domain-Driven Design (DDD)
DI configuration often becomes verbose, repetitive, and difficult to maintain.
Over time, teams start experiencing the following issues:
Startup files filled with dozens or hundreds of service registrations
Cross-cutting concerns such as logging and caching leaking into business logic
DI issues becoming harder to debug, particularly with assembly scanning and decorators
This is where Scrutor helps.
Scrutor is a lightweight extension to the default .NET DI container that adds:
Assembly scanning
Convention-based registration
Decorator support
All without replacing the built-in container. When used correctly, Scrutor keeps Dependency Injection clean, scalable, and explicit—even in large applications.
2. What Problem Does Scrutor Solve?
A typical DI setup in a growing application often looks like this:
services.AddScoped<IUserService, UserService>();
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IProductService, ProductService>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IOrderRepository, OrderRepository>();
This approach introduces several problems:
Boilerplate grows rapidly
Startup files become unreadable
Convention-based architectures are hard to enforce
There is no native support for decorators
Scrutor solves these problems by allowing services to be registered by convention instead of repetition.
3. Key Features of Scrutor
Scrutor extends the built-in DI container with a focused set of features:
Assembly scanning
Automatically discovers and registers services from selected assembliesConvention-based registration
Registers services based on naming conventions or marker interfacesDecorator support
Adds logging, caching, validation, or metrics without modifying business logicBuilt-in DI compatibility
Works seamlessly with Microsoft's DI container without replacing it
4. How to Install Scrutor
Installing Scrutor requires only a single command:
dotnet add package Scrutor
There is no additional configuration required.
5. When Should You Use Scrutor?
Scrutor is a good fit when:
Your application contains many services
You follow Clean Architecture or DDD
You want decorator support without switching to Autofac
You prefer convention over configuration
Scrutor may not be necessary when:
The project is very small
You want every registration to be explicit
You do not need assembly scanning or decorators
6. Scrutor Summary
At a glance, Scrutor:
Extends Microsoft's DI container
Reduces repetitive service registration
Enables clean decorator patterns
Improves scalability
Keeps DI configuration readable and predictable
7. Real-World ASP.NET Core Example (Controllers)
Consider the following project structure:
MyApp.Api
MyApp.Application
├── Services
├── Interfaces
└── Abstractions
MyApp.Infrastructure
├── Repositories
└── Decorators
A recommended best practice is to use a marker interface to define application services:
public interface IApplicationService { }
A service implementation might look like this:
public class UserService : IUserService, IApplicationService
{
private readonly IUserRepository _repository;
public UserService(IUserRepository repository)
{
_repository = repository;
}
public Task<UserDto?> GetUserAsync(int id)
=> _repository.GetByIdAsync(id);
}
Using Scrutor, service registration becomes concise and expressive:
builder.Services.Scan(scan => scan
.FromAssemblies(
typeof(IApplicationService).Assembly,
typeof(IUserRepository).Assembly
)
.AddClasses(c => c.AssignableTo<IApplicationService>())
.AsImplementedInterfaces()
.WithScopedLifetime()
.AddClasses(c => c.Where(t => t.Name.EndsWith("Repository")))
.AsImplementedInterfaces()
.WithScopedLifetime()
);
Join the conversation! Your thoughts help the community grow.