Dependency Injection (DI) is a cornerstone of modern .NET applications, ensuring loose coupling, testability, and maintainability. However, traditional DI configurations can quickly become verbose and boilerplate-heavy. Developers often find themselves manually registering every service, leading to cluttered Program.cs
files and a tedious onboarding experience. Campsis.AutoInject comes to the rescue!
Campsis.AutoInject is a lightweight yet powerful automatic DI registration library that eliminates boilerplate code, making .NET DI effortless and intuitive. Here we explore the why, how, and real-world benefits of using Campsis.AutoInject in your next project.
The Problem with Manual DI
Let's look at a standard .NET application with multiple services:
services.AddScoped<IUserService, UserService>();
services.AddSingleton<ICacheService, MemoryCacheService>();
services.AddTransient<ILogger, Logger>();
For every new service, you have to:
- Remember to register it in Program.cs.
- Choose the correct lifecycle (Scoped, Singleton, Transient).
- Handle service variations (e.g., multiple implementations).
This process is not only redundant but also error-prone — if you forget to register a service, runtime errors will be the consequence.
Campsis.AutoInject automates this process by scanning assemblies for annotated classes and registering them accordingly.
How It Works
Simply annotate your services with SingletonAttribute
, ScopedAttribute
, or TransientAttribute
like this:
[Singleton(typeof(IUserService))]
public class UserService : IUserService { }
[Scoped(typeof(ICacheService))]
public class MemoryCacheService : ICacheService { }
[Transient(typeof(ILogger))]
public class Logger : ILogger { }
Then, in Program.cs, just call
builder.Services.UseAutoInjection();
Now Campsis.AutoInject scans your assembly, finds the annotated services, and registers them automatically for you.
Injecting Multiple Storage Implementations
Example:
[Singleton(typeof(IStorageBroker), WithKey : "SQL")]
public class SqlStorageBroker : IStorageBroker { }
[Singleton(typeof(IStorageBroker), WithKey : "MONGO")]
public class MongoStorageBroker : IStorageBroker { }
Then inject the appropriate implementation using FromKeyedServices
:
[Singleton(typeof(IStudentService))]
public class StudentService(
[FromKeyedServices("SQL")] IStorageBroker sqlStorageBroker,
[FromKeyedServices("MONGO")] IStorageBroker mongoStorageBroker) : IStudentService
{
public ValueTask<string> InsertStudentIntoMongoAsync(object student) =>
mongoStorageBroker.InsertStudentAsync(student);
public ValueTask<string> InsertStudentIntoSQLAsync(object student) =>
sqlStorageBroker.InsertStudentAsync(student);
}
This allows seamless switching between different implementations at runtime.
Install the library via NuGet package manager or via CLI:
dotnet add package Campsis.AutoInject