VersionFlow.Extensions.DI 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package VersionFlow.Extensions.DI --version 1.0.0
                    
NuGet\Install-Package VersionFlow.Extensions.DI -Version 1.0.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="VersionFlow.Extensions.DI" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="VersionFlow.Extensions.DI" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="VersionFlow.Extensions.DI" />
                    
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 VersionFlow.Extensions.DI --version 1.0.0
                    
#r "nuget: VersionFlow.Extensions.DI, 1.0.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 VersionFlow.Extensions.DI@1.0.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=VersionFlow.Extensions.DI&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=VersionFlow.Extensions.DI&version=1.0.0
                    
Install as a Cake Tool

VersionFlow.Extensions.DI

Version 1.0.0 · .NET 10+ · MIT

Attribute-based registration for Microsoft dependency injection. This package works independently of VersionFlow.Core and the CQRS extension.

<PackageReference Include="VersionFlow.Extensions.DI" Version="1.0.0" />

Concrete and interface registrations

using Microsoft.Extensions.DependencyInjection;
using VersionFlow.Extensions.DI;

[Service] // Concrete type only; scoped by default
public sealed class MyHandler { }

[Service(typeof(IClock), ServiceLifetime.Singleton)]
public sealed class Clock : IClock { }

[Service(ServiceLifetime.Transient, typeof(IWriter), typeof(IExporter))]
public sealed class Writer : IWriter, IExporter { }

services.AddAttributedServices();

[Service] always registers the concrete class. It does not automatically bind interfaces. Explicit interface/base-type bindings must be assignable from the implementation. The native ServiceLifetime enum supports Scoped, Singleton, and Transient. Each binding owns its instance: scoped bindings cache per scope, singleton bindings cache per provider, and transient resolutions create new instances. Interface and concrete bindings are separate, including for scoped and singleton services.

To opt into interface discovery:

[Service(ServiceLifetime.Scoped, AsImplementedInterfaces = true)]
public sealed class MyService : IMyService, IAnotherService { }

Discovery includes inherited and closed generic interfaces, excludes IDisposable/IAsyncDisposable, and deduplicates explicit bindings.

Select assemblies

services.AddAttributedServices(typeof(MyHandler).Assembly);
services.AddAttributedServicesFromAssemblyContaining<MyHandler>();

The parameterless overload scans the immediate calling assembly. Prefer explicit assemblies inside shared startup helpers. Only marked classes are registered, and attributes are not inherited.

Repeated scans are idempotent. Existing identical service-type/implementation-type/lifetime registrations are reused; conflicting registrations are rejected before the collection is changed. Competing implementations for one contract require deliberate native DI registration instead. Constructors are not invoked during scanning.

Integration and limitations

For VersionFlow class families, use [Service] without binding the shared versioned interface: VersionFlow registers that interface's facade separately. CQRS interfaces can be explicitly bound like any other interface; this package does not reference or require CQRS.

Types must be closed concrete classes with public constructors. Register open generics through native DI. Scanning uses reflection and carries trimming warnings. Assembly loader failures are reported rather than silently dropping registrations. Native DI scope validation applies. Every binding is an implementation-type registration; there are no forwarding factories that would cause DI to track the same disposable instance twice. Each instance created by these registrations is disposed once by its owning scope/provider. Use CreateAsyncScope and await using for asynchronous-only disposables. If a class supports both IDisposable and IAsyncDisposable, asynchronous scope/provider disposal calls DisposeAsync, while synchronous disposal calls Dispose.

Binding identity and ownership

[Service(typeof(IWorker))]
public sealed class Worker : IWorker, IDisposable
{
    public void Dispose() { /* release this instance's resources */ }
}

This registers the equivalent of:

services.AddScoped<Worker>();
services.AddScoped<IWorker, Worker>();

Resolving IWorker twice within one scope returns the same instance. Resolving Worker separately creates a different scoped instance. Resolving only IWorker does not create the concrete binding's instance. Both bindings are constructed lazily and independently, and each created instance is disposed exactly once. The same per-binding ownership rule applies to singleton services; transient resolutions always create separate instances.

If two bindings need shared mutable state, inject a separately registered scoped/singleton state service into both. [Service] alone continues to register only the concrete type. Arbitrary factory aliases or manually shared disposable objects added outside this scanner still follow the application's own DI ownership choices.

License

MIT. Copyright (c) 2026 Bradley Ables. The full license is included as LICENSE.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 0 11/13/2026
1.0.0 0 11/13/2026