OverridableDependencyInjection 1.1.0
dotnet add package OverridableDependencyInjection --version 1.1.0
NuGet\Install-Package OverridableDependencyInjection -Version 1.1.0
<PackageReference Include="OverridableDependencyInjection" Version="1.1.0" />
<PackageVersion Include="OverridableDependencyInjection" Version="1.1.0" />
<PackageReference Include="OverridableDependencyInjection" />
paket add OverridableDependencyInjection --version 1.1.0
#r "nuget: OverridableDependencyInjection, 1.1.0"
#:package OverridableDependencyInjection@1.1.0
#addin nuget:?package=OverridableDependencyInjection&version=1.1.0
#tool nuget:?package=OverridableDependencyInjection&version=1.1.0
OverridableDependencyInjection
A .NET extension for Microsoft.Extensions.DependencyInjection that lets you substitute a registered service within one IServiceScope without changing the root provider or its registrations.
Use it for test doubles, request-specific behavior, or temporary implementations within a unit of work. Overrides can be supplied by implementation type, instance, or factory. Regular services, keyed services, and open generic interfaces are supported.
Features
- Substitute a service for one scope without rebuilding the root provider
- Keep the original registration available outside that scope
- Override regular, keyed, and open generic interface services
- Choose an implementation type, provide an instance, or create one with a factory
- Integrate with the familiar
ServiceCollectionandIServiceScopeAPIs
Installation
dotnet add package OverridableDependencyInjection
Quick start
using Microsoft.Extensions.DependencyInjection;
using var provider = new ServiceCollection()
.AddTransient<IExampleService1, ExampleService1A>()
.AddTransient<IExampleService2, ExampleService2>()
.AddOverridability<IExampleService1>()
.BuildServiceProvider();
using (var scope = provider.CreateScope())
{
scope.Override<IExampleService1, ExampleService1B>();
var service = scope.ServiceProvider.GetRequiredService<IExampleService1>();
Console.WriteLine(service is ExampleService1B); // True
}
// The root provider still resolves the original registration.
Console.WriteLine(provider.GetRequiredService<IExampleService1>() is ExampleService1A); // True
Basic API
Register overridable services
var services = new ServiceCollection();
services.AddTransient<IWeatherService, WeatherService>();
services.AddTransient<IAuditService, AuditService>();
services.AddOverridability(typeof(IWeatherService), typeof(IAuditService));
You can also do it with generics:
services.AddOverridability<IWeatherService>();
Override inside a scope
using var scope = provider.CreateScope();
scope.Override<IWeatherService, FakeWeatherService>();
Alternatively, provide an instance:
scope.Override<IWeatherService>(new FakeWeatherService());
Or create the override with a factory. The factory receives the current scope's service provider, so it can resolve scoped dependencies:
scope.Override<IWeatherService>(services =>
new FakeWeatherService(services.GetRequiredService<IWeatherData>()));
Override a service type directly
scope.Override(typeof(IWeatherService), typeof(FakeWeatherService));
Open generic support
Open generic interface registrations can also be overridden. Register the open generic service type with AddOverridability:
var provider = new ServiceCollection()
.AddTransient(typeof(IRepository<>), typeof(Repository<>))
.AddOverridability(typeof(IRepository<>))
.BuildServiceProvider();
using var scope = provider.CreateScope();
scope.Override(typeof(IRepository<>), typeof(FakeRepository<>));
Keyed services
Keyed overrides target the specified key; other keys and unkeyed registrations are not changed:
var provider = new ServiceCollection()
.AddKeyedTransient<IExampleService, ExampleServiceA>("primary")
.AddOverridability(typeof(IExampleService))
.BuildServiceProvider();
using var scope = provider.CreateScope();
scope.OverrideKeyed<IExampleService, ExampleServiceB>("primary");
Important behavior
- Register the service first, then call
AddOverridability(...), and only then build the provider. - An override affects resolutions from the scope where it was configured; dispose the scope when the override is no longer needed.
- Other scopes and the root provider continue to use the original registrations.
- Only service types enabled with
AddOverridabilitycan be overridden. - Open generic overrides require an open generic interface registration.
Example application
The repository includes a working demo app:
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. 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 was computed. 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. net11.0 is compatible. |
| .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 is compatible. |
| .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. |
-
.NETStandard 2.0
- DispatchProxyAdvanced (>= 2.0.10)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
-
.NETStandard 2.1
- DispatchProxyAdvanced (>= 2.0.10)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
-
net10.0
- DispatchProxyAdvanced (>= 2.0.10)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
-
net11.0
- DispatchProxyAdvanced (>= 2.0.10)
-
net6.0
- DispatchProxyAdvanced (>= 2.0.10)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
-
net8.0
- DispatchProxyAdvanced (>= 2.0.10)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.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.