ToolBX.AutoInject
4.0.0-beta.2
dotnet add package ToolBX.AutoInject --version 4.0.0-beta.2
NuGet\Install-Package ToolBX.AutoInject -Version 4.0.0-beta.2
<PackageReference Include="ToolBX.AutoInject" Version="4.0.0-beta.2" />
<PackageVersion Include="ToolBX.AutoInject" Version="4.0.0-beta.2" />
<PackageReference Include="ToolBX.AutoInject" />
paket add ToolBX.AutoInject --version 4.0.0-beta.2
#r "nuget: ToolBX.AutoInject, 4.0.0-beta.2"
#:package ToolBX.AutoInject@4.0.0-beta.2
#addin nuget:?package=ToolBX.AutoInject&version=4.0.0-beta.2&prerelease
#tool nuget:?package=ToolBX.AutoInject&version=4.0.0-beta.2&prerelease

AutoInject
A lightweight .NET library designed to make it easier for you to inject services without having to add a new line to a configuration class every time you create an injectable service.
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTransient<ISomeService, SomeService>();
builder.Services.AddScoped<ISomeOtherService, SomeOtherService>();
builder.Services.AddSingleton<IAnotherService, AnotherService>();
builder.Services.AddSingleton<IYetAnotherService, YetAnotherService>();
//TODO Remember to add new services here manually like some sort of animal
What year is this? 2008? What if you have dozens or hundreds of services to inject? With [AutoInject] you can instead do it like this.
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddAutoInjectServices();
public interface ISomeService { }
[AutoInject(ServiceLifetime.Transient)]
public class SomeService : ISomeService { }
public interface ISomeOtherService { }
[AutoInject(ServiceLifetime.Scoped)]
public class SomeOtherService : ISomeOtherService { }
public interface IAnotherService { }
//It uses Singleton by default so no need to specify it
[AutoInject]
public class AnotherService : IAnotherService { }
public interface IYetAnotherService { }
//But knock yourself out if that's what you're into
[AutoInject(ServiceLifetime.Singleton)]
public class YetAnotherService : IYetAnotherService { }
AutoInject also supports injection via a base class rather than an interface. You have to use the generic AutoInject<T> attribute so that it knows what class to inject itself as.
public abstract class AbstractGreeter
{
public abstract string Greet();
}
[AutoInject<AbstractGreeter>]
public class ConcreteGreeter : AbstractGreeter, IWeirdGreeter
{
public override string Greet() => "Hello, theoretically";
}
Getting started
Placing [AutoInject] attributes on every class in your project by itself will do very little (nothing) if you don't configure it properly. You must add the following line to your startup code in order for AutoInject to work :
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddAutoInjectServices();
This will also add AutoInject support for every other loaded assembly so you only need to call it once and everything that uses the [AutoInject] attribute everywhere will be injected.
You can also register services from a specific assembly :
builder.Services.AddAutoInjectServices(typeof(SomeType).Assembly);
How it works
As of version 4.0.0, AutoInject uses a Roslyn source generator to produce DI registration code at compile time. This means:
- No runtime reflection to scan assemblies for attributed types
- Faster application startup
- Compile-time errors when service types can't be resolved (instead of runtime exceptions)
The source generator runs during compilation and emits a Register method containing all the ServiceDescriptor registrations for your [AutoInject]-attributed classes.
Project setup
Any project that contains [AutoInject]-attributed classes needs a reference to both AutoInject and its source generator. When consuming AutoInject as a NuGet package, the generator is included automatically. When using project references, you need to reference the generator project as well:
<ProjectReference Include="..\AutoInject\AutoInject.csproj" />
<ProjectReference Include="..\AutoInject.Generators\AutoInject.Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
Overriding default lifetime
By default, that is if you don't specify anything and just use [AutoInject], your services will be injected as Singleton. You can override this behavior by using AutoInjectOptions when adding AutoInject support in your startup code.
builder.Services.AddAutoInjectServices(new AutoInjectOptions { DefaultLifetime = ServiceLifetime.Scoped });
Automatic type resolution vs explicit
The generic AutoInject<T> should be used whenever there is ambiguity between two or more types. Here is how AutoInject will otherwise resolve your types for injection :
- If the class has only one implementation or base class, that implementation or base class is used
- From here on, base types will be ignored and only interfaces will be considered
- If the class has multiple implementations, it will first look for
"IMyName" - If it does not implement an
"IMyName"interface, it will look for an interface with a similar name (It's not very smart or reliable and I would avoid defaulting to this as much as possible!) - Emits a compile-time error since it can't possibly guess which interface or base type to use
Using AutoInject<T> will bypass automatic resolution entirely. I don't necessarily recommend using AutoInject<T> for every use case but it's quite all right if you want to always be absolutely certain. I personally only use it as a last resort and default to regular AutoInject.
Breaking changes in 4.0.0
- Source generator replaces runtime reflection. The
ToolBX.Reflection4Humans.TypeFetcherdependency has been removed entirely. Service type resolution now happens at compile time. GetAutoInjectServices<T>()has been removed. UseIEnumerable<T>from the DI container instead (e.g.serviceProvider.GetServices<T>()).- Runtime exceptions are now compile-time diagnostics. If a service type can't be resolved (no interface, ambiguous names, etc.), you'll get a compiler error instead of a runtime exception.
AutoInjectServiceNotFoundExceptionhas been removed along with all resource files (Exceptions.resx, etc.).Microsoft.Extensions.Configuration.Json,Microsoft.Extensions.Configuration.Binder, andMicrosoft.Extensions.Optionspackage dependencies have been removed.
Core of the ToolBX micro framework
[AutoInject] is used by every ToolBX library that requires DI and it may not have to be manually added to your project if you already use one such library. It ensures that all ToolBX types are always injected no matter what. I do encourage you to hop on the train and use it as well but it's ultimately your decision which the framework respects by not tying you down in any way.
AddAutoInjectServices is never called by a ToolBX library so you always have to do that one step yourself.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.3)
NuGet packages (13)
Showing the top 5 NuGet packages that depend on ToolBX.AutoInject:
| Package | Downloads |
|---|---|
|
ToolBX.Eloquentest
A simple to use .NET unit testing framework built on top of MSTest and Moq. It also includes built-in support for services that are injected using [AutoInject]. |
|
|
ToolBX.Mathemancy
A bundle for generic geometry types such as Vector2<T>, Size<T> and Rectangle<T> |
|
|
ToolBX.NetAbstractions
Abstractions for .NET base types such as File and Directory to provide easier means to mock low-level operations. |
|
|
ToolBX.Mathemancy.Randomness
Services that generate random numbers and such. |
|
|
ToolBX.AssemblyInitializer
Helps decouple initialization logic by splitting it into AssemblyInitializer classes. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0-beta.2 | 55 | 3/6/2026 |
| 4.0.0-beta.1 | 37 | 3/5/2026 |
| 3.0.1 | 2,229 | 9/30/2024 |
| 3.0.1-beta1 | 139 | 9/28/2024 |
| 3.0.0 | 7,040 | 9/26/2024 |
| 3.0.0-beta2 | 508 | 9/23/2024 |
| 3.0.0-beta1 | 155 | 9/23/2024 |
| 2.2.0 | 11,057 | 1/11/2024 |
| 2.2.0-beta7 | 893 | 1/7/2024 |
| 2.2.0-beta6 | 455 | 12/14/2023 |
| 2.2.0-beta5 | 432 | 12/12/2023 |
| 2.2.0-beta4 | 459 | 11/16/2023 |
| 2.2.0-beta3 | 368 | 10/21/2023 |
| 2.2.0-beta2 | 438 | 7/26/2023 |
| 2.2.0-beta1 | 484 | 7/26/2023 |
| 2.1.1 | 7,019 | 10/24/2023 |
| 2.1.1-beta1 | 326 | 10/21/2023 |
| 2.1.0 | 6,330 | 7/28/2023 |
| 2.1.0-beta1 | 464 | 6/28/2023 |
| 2.0.2 | 3,687 | 6/19/2023 |