PsdExtensions.BootstrapModules
1.0.0
dotnet add package PsdExtensions.BootstrapModules --version 1.0.0
NuGet\Install-Package PsdExtensions.BootstrapModules -Version 1.0.0
<PackageReference Include="PsdExtensions.BootstrapModules" Version="1.0.0" />
<PackageVersion Include="PsdExtensions.BootstrapModules" Version="1.0.0" />
<PackageReference Include="PsdExtensions.BootstrapModules" />
paket add PsdExtensions.BootstrapModules --version 1.0.0
#r "nuget: PsdExtensions.BootstrapModules, 1.0.0"
#:package PsdExtensions.BootstrapModules@1.0.0
#addin nuget:?package=PsdExtensions.BootstrapModules&version=1.0.0
#tool nuget:?package=PsdExtensions.BootstrapModules&version=1.0.0
How do I use it?
First, lets create some models to work with
public sealed class HostModule : HostBootstrapModule
{
public override Task ConfigureAsync(IHostBuilder builder, BootstrapParameters parameters)
{
builder.ConfigureServices(b =>
{
b.AddHostedService<MyBackgroundService>();
});
return Task.CompletedTask;
}
}
public sealed class MyBackgroundService : BackgroundService
{
private readonly ILogger<MyBackgroundService> _logger;
public MyBackgroundService(ILogger<MyBackgroundService> logger)
{
_logger = logger;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Hello, World!");
return Task.CompletedTask;
}
}
Now lets run it
// Program.cs
var modules = new BootstrapModules<IHostBuilder>();
var builder = Host.CreateDefaultBuilder();
await modules.ConfigureAsync(builder);
var app = builder.Build();
await app.RunAsync();
Consider these constraints:
- A Module must be an non-static, non-abstract
class. - A Module must implement the
BootstrapModule<>base class. - A Module must contain a public empty constructor.
- A Module must implement the exact types that will be used later. Assignable base types are not supported for performance reasons.
Example of an unsupported assignable base type approach:
public sealed class MyModule : BootstrapModule<IServiceCollection>
{ ... }
// here is where the issue lies;
// even though ServiceCollection is assignable to IServiceCollection
// native comparer of generic types does not know that
// so in that case Type<IServiceCollection> will NOT equal Type<ServiceCollection>
var modules = new BootstrapModules<ServiceCollection>();
// correct approach
var modules = new BootstrapModules<IServiceCollection>();
This is also the case for .UseAsync<TApp> method, where TApp must be a complete match with the target type of a module.
Custom builders for modules
public sealed class MyCustomModule : BootstrapModule<MyCustomBuilder>
{
public override Task ConfigureAsync(MyCustomBuilder builder, BootstrapParameters parameters)
{
return Task.CompletedTask;
}
}
With a produced app support
public sealed class MyCustomModule : BootstrapModule<MyCustomBuilder, MyCustomApp>
{
public override Task ConfigureAsync(MyCustomBuilder builder, BootstrapParameters parameters)
{
return Task.CompletedTask;
}
public override Task UseAsync(MyCustomApp app, BootstrapParameters parameters)
{
return Task.CompletedTask;
}
}
How to use the produced app in the modules
var modules = new BootstrapModules<IHostBuilder>();
var builder = Host.CreateDefaultBuilder();
await modules.ConfigureAsync(builder);
var app = builder.Build();
await modules.UseAsync(app);
await app.RunAsync();
.ConfigureAsync can be skipped all along if needed
var modules = new BootstrapModules<IHostBuilder>();
var builder = Host.CreateDefaultBuilder();
var app = builder.Build();
await modules.UseAsync(app, ignoreConfiguration: true);
await app.RunAsync();
Group keys
You can seperate certain modules by keys. Key is an object, meaning you can provide a string, enum (recommended), or any other object.
enum ModuleKeys { Primary, Secondary }
[BootstrapModuleOptions(GroupKeys = [ModuleKeys.Primary])]
public sealed class FirstHostModule : HostBootstrapModule
{ ... }
[BootstrapModuleOptions(GroupKeys = [ModuleKeys.Secondary])]
public sealed class SecondHostModule : HostBootstrapModule
{ ... }
[BootstrapModuleOptions(GroupKeys = [ModuleKeys.Primary, ModuleKeys.Secondary])]
public sealed class SharedHostModule : HostBootstrapModule
{ ... }
Now you can filter the modules
var options = new BootstrapModulesOptions()
{
GroupKey = ModuleKeys.Primary
}
var modules = new BootstrapModules<IHostBuilder>();
var builder = Host.CreateDefaultBuilder();
await modules.ConfigureAsync(builder, options);
var app = builder.Build();
await app.RunAsync();
Orders
You can configure the execution sequence of the modules. By default the execution order for each module is set to 0, meaning the sequence is undefined.
// First
[BootstrapModuleOptions(ExecutionOrder = -1)]
public sealed class SecondHostModule : HostBootstrapModule
{ ... }
// Second
[BootstrapModuleOptions(ExecutionOrder = 0)]
public sealed class FirstHostModule : HostBootstrapModule
{ ... }
// Third
[BootstrapModuleOptions(ExecutionOrder = 1)]
public sealed class SecondHostModule : HostBootstrapModule
{ ... }
Discovery assembly filtering
By default, the discoverer will search for the modules within the assembly that called the .ConfigureAsync()/.UseAsync() methods, OR the assembly that instantiated the BootstrapModulesOptions object.
BootstrapModulesOptions stores the assembly reference, but if options are not provided, .ConfigureAsync()/.UseAsync() methods create a default one, which brings the same result.
But this doesn't always have to be the case.
var options = new BootstrapModulesOptions()
{
AssemblyFilter = (a) => a.FullName?.StartsWith(nameof(MyNamespace)) == true
}
This will filter out the unnecessary assemblies from the AppDomain, which will improve the performance of your application.
Parameters
We can provide parameters to the .ConfigureAsync()/.UseAsync() methods for the target modules.
var options = new BootstrapModulesOptions()
{
ParameterConfiguration = (b) =>
{
b.AddParameter("key", "value");
b.AddParameter(myUniqueObject);
}
};
Obtaining the parameters
public sealed class MyModule : HostBootstrapModule
{
public override Task ConfigureAsync(IHostBuilder builder, BootstrapParameters parameters)
{
object? param = parameters.GetParameter("key");
// OR
string? stronglyTypedParam = parameters.GetParameter<string>("key");
// OR
string? keylessParam = parameters.GetParameter<string>();
return Task.CompletedTask;
}
}
Important notes
- Parameter's key, as well as the value, are both of type
object. - If you were to provide a key-less parameter (as shown in the example on the second line), the value's type must be unique.
Nuget
https://www.nuget.org/packages/PsdExtensions.BootstrapModules
| 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.Hosting.Abstractions (>= 10.0.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on PsdExtensions.BootstrapModules:
| Package | Downloads |
|---|---|
|
PsdExtensions.BootstrapModules.AspNetCore
An extension library for PsdExtensions.BootstrapModules that includes template specifically designed for AspNetCore. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 28 | 1/25/2026 |