DI integration with AddFiltering¶
What this does¶
When the consumer assembly references Microsoft.Extensions.DependencyInjection.Abstractions, the source generator emits an IServiceCollection.AddFiltering() extension method. That method registers every [GenerateFilter<TEntity>] class in the assembly as a singleton IFilterDefinition<TEntity>. Controllers and services then take an IFilterDefinition<User> (or any other entity) by constructor injection — no manual services.AddSingleton<IFilterDefinition<User>, UserFilter>() lines.
When to use¶
Any DI-using app: ASP.NET Core, Worker Service, generic-host console apps. Filter classes are stateless after construction (the generator emits read-only metadata at compile time), so singleton lifetime is the right default.
Minimal code¶
Lifted from samples/UserManagement.WebApi/Program.cs:
using Filtering.Net;
using Microsoft.EntityFrameworkCore;
using UserManagement.WebApi.Data;
using UserManagement.WebApi.Json;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("AppDb")!));
// One call registers every [GenerateFilter<T>] partial as IFilterDefinition<T>.
builder.Services.AddFiltering();
var app = builder.Build();
app.MapControllers();
app.Run();
A controller injects the typed definition:
public sealed class UsersController(IFilterDefinition<User> userFilter) : ControllerBase
{
private readonly IFilterDefinition<User> _userFilter = userFilter;
// ...
}
Variations¶
AddFiltering(IJsonTypeInfoResolver)— overload that accepts aJsonSerializerContextfor AOT/trim-clean typed-value JSON deserialization. The sample app usesbuilder.Services.AddFiltering(SampleJsonContext.Default);. See Trim / AOT-clean setup.- Multiple consumer assemblies — the generator emits one
AddFilteringper assembly. If you split filter classes across assemblies, callAddFilteringonce per assembly. - Manual registration — if you need a non-singleton lifetime or a decorator, register
IFilterDefinition<T>manually and skipAddFiltering()for that type.
Pitfalls¶
- The
AddFilteringextension is only emitted when the consumer assembly referencesMicrosoft.Extensions.DependencyInjection.Abstractions. Without that reference,services.AddFiltering()won't compile and you'd register filters by hand. This is intentional — the generator avoids forcing a DI dependency on consumers that don't want one. - The extension lives in the assembly's root namespace by default. If two consumer assemblies both define
AddFilteringand you reference both, resolve the ambiguity by qualifying the call site (or moving filter classes into a single assembly). AddFilteringdoes not registerDbContextor any data-access services for you. Wire those separately as the sample shows.