Introduction
Source-generated Microsoft.Extensions.DependencyInjection registrations declared with attributes.
Immediate.Injections turns attributes on your classes into ordinary Microsoft.Extensions.DependencyInjection registration calls, written at compile time. You mark
a class with a lifetime attribute, call one generated extension method at startup, and the
container is wired — no assembly scanning, no reflection, no convention magic to debug.
Installation
dotnet add package Immediate.Injections The package ships the attributes, the generator and the analyzers together. Nothing else is
required at runtime beyond Microsoft.Extensions.DependencyInjection.Abstractions, which comes
with the package.
Supported target frameworks are net8.0, net9.0 and net10.0. See Package compatibility for the full matrix.
Prerequisites
Unlike Immediate.Apis, Immediate.Cache and Immediate.Validations, this package does not require Immediate.Handlers. It is a standalone dependency-injection helper and can be used in a project that has no other ImmediatePlatform package installed.
A minimal example
using Immediate.Injections.Shared;
public interface ITodoRepository
{
Task<Todo?> GetAsync(int id);
}
[RegisterScoped<ITodoRepository>]
public sealed class TodoRepository(TodoDbContext context) : ITodoRepository
{
public Task<Todo?> GetAsync(int id) =>
context.Todos.FirstOrDefaultAsync(t => t.Id == id);
}var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTodoServices();AddTodoServices is generated. The Todo in the middle is the assembly identifier — by default
the assembly name with ., spaces and - removed, so a project named Todo gets AddTodoServices and a project named Todo.Web gets AddTodoWebServices.
The generated body is a literal list of ServiceDescriptor calls:
global::Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.Add(
services,
global::Microsoft.Extensions.DependencyInjection.ServiceDescriptor.Scoped(
typeof(global::ITodoRepository),
typeof(global::TodoRepository)
)
);Where to go next
The three lifetime attributes, their three forms, and the generated extension method.
ServiceType vs RegistrationStrategy, and how duplicates are handled.
Register and resolve services under a key.
Register a generic class as an open generic and let the container close it.
Custom construction, and sharing one instance across a type and its interfaces.
Hook hand-written registration code into the generated method.
Every attribute property and both enums, in one table.
INJ0001–INJ0012, what triggers each and how to fix it.