Mdk.DISourceGenerator
1.0.0
See the version list below for details.
dotnet add package Mdk.DISourceGenerator --version 1.0.0
NuGet\Install-Package Mdk.DISourceGenerator -Version 1.0.0
<PackageReference Include="Mdk.DISourceGenerator" Version="1.0.0" />
paket add Mdk.DISourceGenerator --version 1.0.0
#r "nuget: Mdk.DISourceGenerator, 1.0.0"
// Install Mdk.DISourceGenerator as a Cake Addin
#addin nuget:?package=Mdk.DISourceGenerator&version=1.0.0
// Install Mdk.DISourceGenerator as a Cake Tool
#tool nuget:?package=Mdk.DISourceGenerator&version=1.0.0
Summary
The DISourceGenerator package is designed to help clean up your service registration code when using the default Dependency Injection (DI) container in .NET. It allows you to use custom attributes to register your services, keeping the DI metadata close to the implementation classes.
- Installation: The package is available on NuGet as Mdk.DISourceGenerator.
- Attribute Usage: The package provides attributes like AddScoped, AddSingleton, and AddTransient for different lifetimes. You can use these attributes on your classes to register them with the DI container. For example,
[AddScoped] class MyClass { ... }
is equivalent toservices.AddScoped<MyClass>();
. - The incremental source generator translates the attributes to registration code for the default DI container.
DISourceGenerator
If you have a lot of services registered in the default DI container, your registration code can become some sort of a mess.
Using custom attributes can make your registration much cleaner. Attributes with registration information keep DI metadata close to the implementation classes the attributes are assigned to.
DISourceGenerator generates service registration source code based on attributes assigned to classes. Adding one line of code in ConfigureServices registers all services both in the host assembly as in directly and transitively referenced assemblies.
In the examples section of this repository a Blazor application and a Minimal API project are added, in which this registration strategy is implemented.
Installation
The source generator is available as a NuGet package: Mdk.DISourceGenerator
Attribute usage
Following examples focus on scoped registration. Use AddSingleton or AddTransient for other lifetimes.
Simple classes and interfaces
[AddScoped]
class MyClass { ... }
equals to services.AddScoped<MyClass>();
[AddScoped<IMyInterface>]
class MyClass: IMyInterface { ... }
equals to services.AddScoped<IMyInterface, MyClass>();
Generic attributes require C# 11. If you are still on a earlier version use [AddScoped(typeof(IMyInterface))]
Multiple attributes on one class
[AddScoped<IMyInterface1>]
[AddScoped<IMyInterface2>]
class MyClass: IMyInterface1, IMyInterface2 { ... }
equals to
services.AddScoped<IMyInterface1, MyClass>();
services.AddScoped<IMyInterface2, MyClass>();
Generic classes and interfaces
Unbound generic registration:
[AddScoped]
class MyClass<T> { ... }
equals to services.AddScoped(typeof(MyClass<>));
[AddScoped(typeof(IMyInterface<>))]
class MyClass<T>: IMyInterface<T> { ... }
equals to services.AddScoped(typeof(IMyInterface<>), typeof(MyClass<>));
Bound generic registration:
[AddScoped<MyClass<int>>]
class MyClass<T> { ... }
equals to services.AddScoped<MyClass<int>>();
[AddScoped<IMyInterface<int>>]
class MyClass<T>: IMyInterface<T> { ... }
equals to services.AddScoped<IMyInterface<int>, MyClass<int>>();
Multiple generic type parameters
Multiple generic type parameters are also supported, for example:
[AddScoped]
class MyClass<T, U> { ... }
equals to services.AddScoped(typeof(MyClass<,>));
Generated source
If there's a direct or transitive reference to the DISourceGenerator package and DIAttributes are used in an assembly, a registration method is generated per assembly.
This method registers all services in an assembly and also includes static method calls to all generated methods in referenced assemblies, both direct and transitive:
// <auto-generated />
using Microsoft.Extensions.DependencyInjection;
namespace Mdk.DISourceGenerator;
public static partial class DIRegistrations
{
public static IServiceCollection RegisterServicesMinimalApi(this IServiceCollection services)
{
if (registeredServicesMinimalApi)
return services;
services.AddScoped<global::MinimalApi.MinimalApiService>();
services.RegisterServicesBusinessBaseLogic();
services.RegisterServicesBusinessLogic();
registeredServicesMinimalApi = true;
return services;
}
private static bool registeredServicesMinimalApi;
}
The naming convention for the static method is DIRegistrations.RegisterServices{AssemblyName}(...).
So in startup only one method call is needed to register all services based on DIAttributes:
using Mdk.DISourceGenerator;
builder.Services.RegisterServicesMinimalApi();
Inspecting generated source code
In the Solution Explorer of Visual Studio generated source can be found in:
{AssemblyName} > Dependencies > Analyzers > Mdk.DISourceGenerator > Mdk.DISourceGenerator.DISourceGenerator > DISourceGenerator.{AssemblyName}.g.cs
You can make the generated source more visible in your project and even add the generated files to source control. Copy and paste following PropertyGroup and ItemGroup into the .csproj-file.
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
<None Include="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
</ItemGroup>
This configuration is for all source generators in the project. Use git ignore to prevent output of (other) source generators to be included in source control.
References
Articles
- Source Generators in C# by Code Maze
- Series: Creating a source generator by Andrew Lock
- Series: Incremental Roslyn Source Generators In .NET 6: Code Sharing Of The Future by Pawel Gerr
- Debugging Source Generators by infinum
Repositories
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Mdk.DIAttributes (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.