Snowberry.DependencyInjection 5.2.0

dotnet add package Snowberry.DependencyInjection --version 5.2.0
                    
NuGet\Install-Package Snowberry.DependencyInjection -Version 5.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Snowberry.DependencyInjection" Version="5.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Snowberry.DependencyInjection" Version="5.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Snowberry.DependencyInjection" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Snowberry.DependencyInjection --version 5.2.0
                    
#r "nuget: Snowberry.DependencyInjection, 5.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Snowberry.DependencyInjection@5.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Snowberry.DependencyInjection&version=5.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Snowberry.DependencyInjection&version=5.2.0
                    
Install as a Cake Tool

License NuGet Version

Snowberry.DependencyInjection

A lightweight, easy-to-use IoC container for .NET. Warm resolution runs through a compiled per-service resolver graph (allocation parity with Microsoft.Extensions.DependencyInjection), and unlike build-once providers the container stays mutable, so you can add, remove, and overwrite registrations at any time. When you are done configuring, an opt-in Freeze() locks it in for maximum speed.

Install

dotnet add package Snowberry.DependencyInjection

Quick start

using Snowberry.DependencyInjection;
using Snowberry.DependencyInjection.Abstractions.Extensions;

using var container = new ServiceContainer();

container.RegisterSingleton<IFoo, Foo>();
container.RegisterTransient<IBar, Bar>();

var foo = container.GetRequiredService<IFoo>();

Dispose the container (Dispose() or await container.DisposeAsync()) when you are done. It disposes the instances it created.

Service lifetimes

Lifetime Description
Singleton One instance for the container's lifetime.
Transient A new instance on every resolve.
Scoped One instance per scope.
container.RegisterSingleton<IFoo, Foo>();
container.RegisterTransient<IBar, Bar>();
container.RegisterScoped<IBaz, Baz>();

Register a pre-built instance. Instances you supply are not disposed by the container:

container.RegisterSingleton<IFoo>(instance: new Foo());

Scopes

container.RegisterScoped<IScopedType, ScopedType>();

using (var scope = container.CreateScope())
{
    // Created for this scope and disposed when the scope is disposed.
    var svc = scope.ServiceProvider.GetRequiredService<IScopedType>();
}

Resolving a scoped service directly from the container uses the container's own root scope (disposed with the container).

Keyed services

container.RegisterTransient<ITestService, TestServiceA>("_KEY0_");

var svc = container.GetRequiredKeyedService<ITestService>("_KEY0_");

Open generic types

container.Register(typeof(IRepository<>), typeof(Repository<>), serviceKey: null, lifetime: ServiceLifetime.Transient, singletonInstance: null);

var repo = container.GetRequiredService<IRepository<User>>();

Overwriting registrations

By default a registration can be replaced. Pass ServiceContainerOptions.ReadOnly to forbid overwrites.

var container = new ServiceContainer(ServiceContainerOptions.Default & ~ServiceContainerOptions.ReadOnly);

container.RegisterTransient<IService, Impl>();
// Replaces the registration. Previously-created instances are still disposed as usual.
container.RegisterSingleton<IService, OtherImpl>();

Injection attributes

InjectAttribute ([Inject])

Injects a service into a property during construction.

  • Valid on properties only. Cannot be applied more than once. Inherited.
  • Required by default. If the service is not registered, resolution throws. Pass isRequired: false to make it optional, in which case an unregistered service leaves the property as its default (null) instead of throwing.
  • Can be combined with [FromKeyedServices].
[Inject]
public ITestService Service { get; set; }

[Inject(isRequired: false)]
public ILogger? OptionalLogger { get; set; }

FromKeyedServicesAttribute ([FromKeyedServices])

Selects which keyed service to use for a property or constructor parameter.

  • Valid on properties and parameters. Cannot be applied more than once. Inherited.
  • On a property, combine with [Inject]; on a constructor parameter it works on its own.
// Property:
[Inject]
[FromKeyedServices("_KEY1_")]
public ITestService? KeyedService { get; set; }

// Constructor parameter:
public MyService([FromKeyedServices("_KEY1_")] ITestService service) { ... }

PreferredConstructorAttribute ([PreferredConstructor])

Specifies which constructor the container should use to instantiate a type.

  • Valid on constructors only. Cannot be applied more than once. Not inherited.
  • Not needed when the type has a single constructor.
public class MyService
{
    public MyService() { }

    [PreferredConstructor]
    public MyService(IDependency dependency) { ... }
}

Validation

Check the whole registered graph up front ("fail fast at startup") without constructing any instances. The container stays mutable; re-run after further changes.

// Throws ServiceValidationException listing every problem.
container.Validate();

// Or collect problems without throwing.
if (!container.TryValidate(out var errors))
{
    foreach (var error in errors)
        Console.WriteLine(error); // missing dependency / circular dependency / no usable constructor
}

Missing required dependencies and dependency cycles surface as exceptions at resolve time too (ServiceTypeNotRegistered, CircularDependencyException).

Freezing (opt-in lock-in for maximum speed)

When configuration is complete, Freeze() locks the container for the fastest resolves:

container.Freeze();                 // validates first; pass Freeze(validate: false) to skip
bool locked = container.IsFrozen;

container.RegisterTransient<IBaz, Baz>(); // throws ServiceRegistryReadOnlyException
  • Freeze() validates by default. It runs Validate() first; on a problem it throws ServiceValidationException and the container stays unfrozen and mutable. Use Freeze(validate: false) to skip.
  • One-way and idempotent (re-freezing is a no-op and does not re-validate).
  • Stronger than ServiceContainerOptions.ReadOnly, which blocks overwrite only. Freezing blocks all registration changes.
  • Freeze before creating long-lived scopes (scopes created after freezing use the optimized scope cache).
Mode Add / remove / overwrite Warm-resolve speed
Mutable (default) Yes Fast: beats MS.DI on singleton/scoped, parity on simple transients
Frozen (Freeze()) No (locked) Fastest: full-graph inlining, baked singletons, optimized scopes

How it works

Resolution is backed by a compiled per-service resolver graph: the first resolve of a type compiles and caches a delegate, and every warm resolve afterward is a dictionary lookup plus a delegate call (0 allocations for warm singleton/scoped). See docs/ARCHITECTURE.md for diagrams of the resolver graph and the mutable → frozen lifecycle.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Snowberry.DependencyInjection:

Package Downloads
Snowberry.Mediator.DependencyInjection

Extension for the main package to work with `Snowberry.DependencyInjection`.

Snowberry.Mediator.OpenTelemetry

Snowberry.DependencyInjection integration for Snowberry.Mediator OpenTelemetry.

GitHub repositories

This package is not used by any popular GitHub repositories.