![]() |
VOOZH | about |
dotnet add package Rystem.DependencyInjection.Web --version 10.0.8
NuGet\Install-Package Rystem.DependencyInjection.Web -Version 10.0.8
<PackageReference Include="Rystem.DependencyInjection.Web" Version="10.0.8" />
<PackageVersion Include="Rystem.DependencyInjection.Web" Version="10.0.8" />Directory.Packages.props
<PackageReference Include="Rystem.DependencyInjection.Web" />Project file
paket add Rystem.DependencyInjection.Web --version 10.0.8
#r "nuget: Rystem.DependencyInjection.Web, 10.0.8"
#:package Rystem.DependencyInjection.Web@10.0.8
#addin nuget:?package=Rystem.DependencyInjection.Web&version=10.0.8Install as a Cake Addin
#tool nuget:?package=Rystem.DependencyInjection.Web&version=10.0.8Install as a Cake Tool
Rystem.DependencyInjection.Web adds a runtime-rebuild layer on top of Rystem.DependencyInjection for ASP.NET Core applications.
The package is built for scenarios where the application must keep serving requests while the underlying IServiceCollection changes at runtime. Instead of treating the container as immutable after startup, it keeps track of the current service collection, rebuilds a fresh provider when needed, and routes later requests through that latest provider.
This is a specialized package. It is most useful for:
Most examples below come from the current source and from the runtime integration tests in src/Core/Test/Rystem.Test.UnitTest/RuntimeServiceProvider/RuntimeServiceProviderTest.cs plus the sample API used by those tests in src/Extensions/Tests/Test/Rystem.Test.TestApi.
dotnet add package Rystem.DependencyInjection.Web
The current 10.x package targets net10.0 and references:
Microsoft.AspNetCore.AppRystem.DependencyInjectionThis package assumes the abstractions from Rystem.DependencyInjection, which in turn builds on the lower-level utility package Rystem.
The package is intentionally small and is organized around two modules.
| Module | Purpose |
|---|---|
RuntimeServiceProvider |
Tracks the current IServiceCollection, current built IServiceProvider, request-time swapping, and rebuild operations |
Fallback |
Integrates with IFactory<T> so missing factory names can register new services and rebuild automatically |
At a high level, the flow is:
AddRuntimeServiceProvider() during service registrationUseRuntimeServiceProvider() after the app is builtIServiceCollection laterRebuildAsync() to build the next providerRegister runtime rebuilding during startup:
builder.Services.AddRuntimeServiceProvider();
var app = builder.Build();
app.UseRuntimeServiceProvider();
This does two important things:
IServiceCollection so it can be mutated laterHttpContext.RequestServices with a scope created from the latest rebuilt providerYou can also choose not to dispose the previous request service provider when the middleware swaps it out:
app.UseRuntimeServiceProvider(disposeOldServiceProvider: false);
That flag matters only if you need to keep the previous request-scoped provider alive longer than the default handoff behavior.
The package keeps global static references to:
IServiceCollectionIServiceProviderIApplicationBuilder used to patch the host-level Services propertyWhen RebuildAsync() runs, it:
WarmUpAsync() on the rebuilt providerThis design means the package is best suited to application-level dynamic composition, not to isolated per-module container ownership.
After setup, you can read either the mutable collection or the latest provider.
IServiceCollection services = RuntimeServiceProvider.GetServiceCollection();
IServiceProvider provider = RuntimeServiceProvider.GetServiceProvider();
GetServiceCollection() also clears the internal read-only flag on the collection before returning it, so later Add... calls can keep modifying the same collection instance.
GetServiceProvider() throws until the runtime provider has been initialized through UseRuntimeServiceProvider().
The simplest runtime update flow is:
await RuntimeServiceProvider
.GetServiceCollection()
.AddSingleton<MyNewService>()
.RebuildAsync();
That pattern comes directly from the test API used by RuntimeServiceProviderTest.
For example, the sample controller checks whether AddedService exists and, if not, registers it and rebuilds immediately:
var value = _serviceProvider.GetService<AddedService>();
if (value == null)
{
await RuntimeServiceProvider.GetServiceCollection()
.AddSingleton<AddedService>()
.RebuildAsync();
}
The integration test confirms the effect:
AddedServiceIf multiple threads may mutate the tracked service collection, use the built-in lock helper:
await RuntimeServiceProvider
.AddServicesToServiceCollectionWithLock(services =>
{
services.AddSingleton(myServiceInstance);
})
.RebuildAsync();
Use this helper when registration can happen concurrently, for example from multiple requests or parallel background tasks.
The runtime tests also exercise this pattern by adding many mocked service types in parallel and rebuilding after each change.
You can rebuild either from the tracked collection instance or through the static shortcut:
await services.RebuildAsync();
await RuntimeServiceProvider.RebuildAsync();
Every rebuild ends by calling WarmUpAsync() on the latest provider, so warm-up actions registered through Rystem.DependencyInjection still participate in the runtime-rebuild flow.
By default, rebuild keeps the current singleton instance values when matching singleton descriptors still exist in the new collection.
await RuntimeServiceProvider.RebuildAsync(preserveValueForSingletonServices: true);
Or disable that behavior:
await RuntimeServiceProvider.RebuildAsync(preserveValueForSingletonServices: false);
That default preservation is why the runtime test can add AddedService while keeping the original ids for already-created singleton services.
The implementation tracks the current number of registered services and only promotes the rebuilt provider if that rebuild still represents the largest service collection seen so far.
Practically, this means that when multiple rebuilds race:
The tests stress this behavior with repeated sequential and parallel rebuilds.
This package becomes especially powerful when combined with IFactory<T> from Rystem.DependencyInjection.
You can register a fallback that reacts when factory.Create(name) is called for an unknown name. Inside that fallback you dynamically add the missing factory registration, rebuild the service provider, and then return the newly available service.
services.AddFactory<Factorized>("1");
services.AddActionAsFallbackWithServiceCollectionRebuilding<Factorized>(async context =>
{
await Task.Delay(1);
var singletonService = context.ServiceProvider.GetService<SingletonService>();
if (singletonService != null)
{
context.ServiceColletionBuilder = serviceCollection =>
serviceCollection.AddFactory<Factorized>(context.Name);
}
});
That exact pattern is used in src/Extensions/Tests/Test/Rystem.Test.TestApi/Extensions/ServiceExtensions.cs.
After this is registered, the first call to an unknown factory name can materialize the missing registration on demand:
var factory = serviceProvider.GetRequiredService<IFactory<Factorized>>();
var created = factory.Create("dynamic-name");
The runtime tests validate this behavior both for one service and for many services in parallel.
There is also a non-generic overload for runtime service types:
RuntimeServiceProvider.AddServicesToServiceCollectionWithLock(sc =>
{
sc.AddActionAsFallbackWithServiceCollectionRebuilding(serviceType, async context =>
{
await Task.Delay(1);
context.ServiceColletionBuilder = inner => inner.AddFactory(serviceType, context.Name);
});
});
await RuntimeServiceProvider.RebuildAsync();
This is useful when the service contract itself is discovered dynamically.
The fallback delegate receives FallbackBuilderForServiceCollection:
| Property | Type | Purpose |
|---|---|---|
Name |
AnyOf<string, Enum>? |
The missing factory name that triggered the fallback |
ServiceProvider |
IServiceProvider |
A fresh scope created from the current runtime provider |
ServiceColletionBuilder |
Action<IServiceCollection> |
The action that will mutate the tracked service collection before rebuild |
Note that the public property name is actually ServiceColletionBuilder in the source, including the typo. The README keeps that spelling because it is the real API surface.
Internally the flow is:
FallbackBuilderForServiceCollectionServiceColletionBuilderAddServicesToServiceCollectionWithLock(...)RebuildAsync()IFactory<T>UseRuntimeServiceProvider() relies on reflection to patch internal hosting fields and to unfreeze the service collection.RebuildAsync() returns the current IServiceProvider, so you can chain additional startup logic after a rebuild.Rystem.DependencyInjection, especially AddFactory(...), warm-up, and service helper APIs.The most useful sources for this package are:
This README is intentionally architecture-first because Rystem.DependencyInjection.Web is not just one extension method. It is a runtime composition model for ASP.NET Core built on top of the base Rystem DI package.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on Rystem.DependencyInjection.Web:
| Package | Downloads |
|---|---|
|
Rystem.Test.XUnit
Rystem is a open-source framework to improve the System namespace in .Net |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.8 | 6,018 | 5/13/2026 |
| 10.0.7 | 227 | 3/26/2026 |
| 10.0.6 | 433,684 | 3/3/2026 |
| 10.0.5 | 186 | 2/22/2026 |
| 10.0.4 | 213 | 2/9/2026 |
| 10.0.3 | 147,983 | 1/28/2026 |
| 10.0.1 | 209,132 | 11/12/2025 |
| 9.1.3 | 324 | 9/2/2025 |
| 9.1.2 | 764,536 | 5/29/2025 |
| 9.1.1 | 97,815 | 5/2/2025 |
| 9.0.32 | 186,755 | 4/15/2025 |
| 9.0.31 | 5,818 | 4/2/2025 |
| 9.0.30 | 88,862 | 3/26/2025 |
| 9.0.29 | 9,021 | 3/18/2025 |
| 9.0.28 | 252 | 3/17/2025 |
| 9.0.27 | 234 | 3/16/2025 |
| 9.0.26 | 269 | 3/13/2025 |
| 9.0.25 | 52,129 | 3/9/2025 |
| 9.0.23 | 226 | 3/9/2025 |
| 9.0.21 | 328 | 3/6/2025 |