Baubit 2025.23.1
The package has been broken down to smaller projects with granular concerns. Look for Baubit.* packages on nuget.
dotnet add package Baubit --version 2025.23.1
NuGet\Install-Package Baubit -Version 2025.23.1
<PackageReference Include="Baubit" Version="2025.23.1" />
<PackageVersion Include="Baubit" Version="2025.23.1" />
<PackageReference Include="Baubit" />
paket add Baubit --version 2025.23.1
#r "nuget: Baubit, 2025.23.1"
#:package Baubit@2025.23.1
#addin nuget:?package=Baubit&version=2025.23.1
#tool nuget:?package=Baubit&version=2025.23.1
Baubit
Introduction
Baubit is a lightweight, modular framework for building scalable and maintainable .NET applications. It provides a clean abstraction for organizing functionality into independently configured modules, supporting recursive loading, dependency injection, and multiple configuration sources.
Why Use Baubit?
- π§© Modular Architecture: Encapsulate related functionality in self-contained units (modules).
- ποΈ Configuration Management: Modules support their own typed configuration with support for JSON, embedded resources, and secrets.
- βοΈ Clean DI Integration: Each module registers services into
IServiceCollection, respecting lifecycle and separation of concerns. - π Recursive Nesting: Modules can declare and load other modules as dependencies.
- π¦ Configurable Bootstrapping: Load and configure modules via JSON, appsettings, code, or embedded resources.
- π§ͺ Testability & Reusability: Modules are isolated and easily testable.
- π‘οΈ Validatable: Not only are modules and configurations validated (in isolation) before loding, modules are checked against the module tree to avoid redundant / missing modules.
π Getting Started
1οΈβ£ Installation
dotnet add package Baubit
π¦ Defining a Module
A Baubit module is a self-contained unit that adds one or more services to the application's IoC container.
public class MyConfiguration : AConfiguration
{
public string MyStringProperty { get; set; }
}
public class MyModule : AModule<MyConfiguration>
{
public MyModule(ConfigurationSource configurationSource) : base(configurationSource) { }
public MyModule(IConfiguration configuration) : base(configuration) { }
public MyModule(MyConfiguration configuration,
List<AModule> nestedModules,
List<IConstraint> constraints) : base(configuration, nestedModules, constraints) { }
public override void Load(IServiceCollection services)
{
var myStrProp = Configuration.MyStringProperty;
services.AddSingleton(new MyService(myStrProp));
//register other services as needed
base.Load(services);
}
}
Configuration for each registered service can be passed via the Module's specific configuration
βοΈ Loading a Module
Baubit supports multiple ways to load modules:
1. Via appsettings.json (Recommended)
appsettings.json Example:
{
"rootModule": [
"type": "Baubit.DI.RootModule, Baubit",
"configurationSource": {
"embeddedJsonResources": [ "MyApp;myConfig.json" ]
}
]
}
Using HostApplicationBuilder
await Host.CreateApplicationBuilder()
.UseConfiguredServiceProviderFactory()
.Build()
.RunAsync();
Using WebApplicationBuilder
var webApp = WebApplication.CreateBuilder()
.UseConfiguredServiceProviderFactory()
.Build();
// Use HTTPS, HSTS, CORS, Auth and other middleware
// Map endpoints
await webApp.RunAsync();
2. Via ConfigurationSource (Direct Code-Based)
Using HostApplicationBuilder
var configSource = new ConfigurationSource { EmbeddedJsonSources = ["MyApp;myConfig.json"] };
await Host.CreateApplicationBuilder()
.UseConfiguredServiceProviderFactory(configSource.Build())
.Build()
.RunAsync();
Using WebApplicationBuilder
var configSource = new ConfigurationSource { EmbeddedJsonSources = ["MyApp;myConfig.json"] };
var webApp = WebApplication.CreateBuilder()
.UseConfiguredServiceProviderFactory(configSource.Build())
.Build();
// Use HTTPS, HSTS, CORS, Auth and other middleware
// Map endpoints
await webApp.RunAsync();
3. Manual DI (Without a Host Builder)
var configSource = new ConfigurationSource { EmbeddedJsonSources = ["MyApp;myConfig.json"] };
var services = new ServiceCollection();
services.AddFrom(configSource); // Loads all modules (recursively) defined in myConfig.json
var serviceProvider = services.BuildServiceProvider();
This approach is particularly useful when used in unit tests. See Baubit.xUnit for developing modular unit tests using Baubit
ποΈ Configuration Sources
Baubit supports a mix of external and embedded configuration options:
β Supported Sources
jsonUriStrings: Local or remote JSON pathsembeddedJsonResources: Embedded resources within assemblieslocalSecrets: User secrets via GUID ID
1. jsonUriStrings
Loads JSON files from paths accessible to the application.
{
"modules": [
{
"type": "...",
"configurationSource": {
"jsonUriStrings": [ "/path/to/myConfig.json" ]
}
}
]
}
2. embeddedJsonResources
Loads JSON configuration embedded as a resource in a .NET assembly.
{
"modules": [
{
"type": "...",
"configurationSource": {
"embeddedJsonResources": [ "MyApp;MyComponent.SubComponent.myConfig.json" ]
}
}
]
}
3. localSecrets
Loads configuration from secrets.json files using a GUID reference (User Secrets ID).
{
"modules": [
{
"type": "...",
"configurationSource": {
"localSecrets": [ "0657aef1-6dc5-48f1-8ae4-172674291be0" ]
}
}
]
}
This resolves to:
<user_secrets_path>/UserSecrets/{ID}/secrets.json
π Combining Multiple Sources
You can merge different configuration sources. Example:
{
"modules": [
{
"type": "...",
"configurationSource": {
"jsonUriStrings": [ "/path/to/myConfig.json" ],
"embeddedJsonResources": [ "MyApp;MyComponent.SubComponent.myConfig.json" ],
"localSecrets": [ "0657aef1-6dc5-48f1-8ae4-172674291be0" ]
}
}
]
}
All sources are merged in order.
β Combining Sources with Explicit Configuration
Itβs also valid to define configuration values explicitly alongside configuration sources. The sources are merged with the explicit keys.
{
"modules": [
{
"type": "...",
"configuration": {
"myConfigurationProperty": "some value"
},
"configurationSource": {
"jsonUriStrings": [ "/path/to/myConfig.json" ],
"embeddedJsonResources": [ "MyApp;MyComponent.SubComponent.myConfig.json" ],
"localSecrets": [ "0657aef1-6dc5-48f1-8ae4-172674291be0" ]
}
}
]
}
This will result in a configuration that combines values from all three sources plus the inline configuration block.
πͺ Nesting Modules
One of Baubit's most powerful features is its ability to recursively load modules, especially from configuration files. This enables complex service registration trees to be configured externally, promoting reusability and modularity.
π Nested Configuration Example
{
"modules": [
{
"type": "<module1>",
"configuration": {
"<module1ConfigProperty>": "some value",
"modules": [
{
"type": "<module2>",
"configuration": {
"module2ConfigProperty": "some value"
}
},
{
"type": "<module3>",
"configuration": {
"module3ConfigProperty": "some value",
"modules": [
{
"type": "<module4>",
"configuration": {
"module4ConfigProperty": "some value"
}
}
]
}
}
]
}
}
]
}
This configuration will load Module 1, along with its nested modules 2, 3, and 4, in a hierarchical manner. Each module can define its own configuration and optionally nest further modules.
π§ This approach allows dynamic and flexible service registration β driven entirely by configuration without changing code.
β Validation
Baubit introduces a powerful validation mechanism to ensure the integrity of your module configurations and their interdependencies.
Configuration Validation
Create your configuration
public class Configuration : AConfiguration
{
public string MyStringProperty { get; init;}
}
Implement the AValidator class to define validation logic for configuration.
public class MyConfigurationValidator : AValidator<Configuration>
{
protected override IEnumerable<Expression<Func<Configuration, Result>>> GetRules()
{
return [config => Result.OkIf(!string.IsNullOrEmpty(config.MyStringProperty), new Error($"{nameof(config.MyStringProperty)} cannot be null or empty")];
}
}
Multiple validators can be defined via the validatorKeys configuration property. Validators for modules can also be defined in the similar fashion
{
"modules": [
{
"type": "...",
"configuration": {
"validatorKeys": [ "MyLib.MyConfigurationValidator, MyLib" ],
"moduleValidatorKeys": [ "MyLib.MyModuleValidator, MyLib" ]
//"myStringProperty" : "" //<not_defined_on_purpose>
}
}
]
}
Module Validation
While modules can also be validated in isolation (similar to shown above), Baubit allows defining constraints under which modules can/cannot be included in a module tree
public class SingularityConstraint<TModule> : IConstraint
{
public string ReadableName => string.Empty;
public Result Check(List<IModule> modules)
{
return modules.Count(mod => mod is TModule) == 1 ? Result.Ok() : Result.Fail(string.Empty).AddReasonIfFailed(new SingularityCheckFailed());
}
}
public class SingularityCheckFailed : AReason
{
}
A module can then simply use these constraints to valide the module tree
public class Module : AModule<Configuration>
{
public Module(ConfigurationSource configurationSource) : base(configurationSource)
{
}
public Module(IConfiguration configuration) : base(configuration)
{
}
public Module(Configuration configuration,
List<Baubit.DI.AModule> nestedModules,
List<IConstraint> constraints) : base(configuration, nestedModules, constraints)
{
}
protected override IEnumerable<IConstraint> GetKnownConstraints()
{
return [new SingularityConstraint<Module>()];
}
}
This allows preventing redundant service registrations and checking module dependencies at bootstrapping
π Roadmap
Future enhancements for Baubit:
- β Configuration Extensions: Support for more configuration sources.
- β Middleware Support: Integrate modules with ASP.NET middleware.
- π§ Logging & Monitoring: Improve logging support within modules.
- π§ Community Contributions: Open-source enhancements and community-driven improvements.
π€ Contributing
Contributions are welcome! If youβd like to improve Baubit:
- Fork the repository.
- Create a new branch (
feature/new-feature). - Submit a pull request with detailed changes.
For major contributions, open an issue first to discuss the change.
π Troubleshooting & FAQs
Q: How do I use multiple modules together?
A: You can initialize multiple modules and inject them into your service container.
Q: Can I override module configurations?
A: Yes! You can extend configurations by passing custom settings to ConfigurationSource.
For more support, open an issue on GitHub.
π Resources
- Samples
- Official Documentation (Coming Soon)
- Issue Tracker: GitHub Issues
- Discussions: GitHub Discussions
Acknowledgments & Inspiration
See ACKNOWLEDGEMENT.md and INSPIRATION.md for details on libraries and ideas that influenced this project.
Copyright
Copyright (c) Prashant Nagoorkar. See LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net9.0
- FluentResults (>= 3.16.0)
- Microsoft.Extensions.Configuration (>= 9.0.5)
- Microsoft.Extensions.Configuration.Json (>= 9.0.5)
- Microsoft.Extensions.Hosting (>= 9.0.5)
- OpenTelemetry.Exporter.Console (>= 1.12.0)
- OpenTelemetry.Extensions.Hosting (>= 1.12.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Baubit:
| Package | Downloads |
|---|---|
|
Baubit.Aggregation
Package Description |
|
|
Baubit.xUnit
Package Description |
|
|
Baubit.Autofac
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 2025.23.1 | 364 | 6/4/2025 | |
| 2025.18.5 | 331 | 5/6/2025 | |
| 2025.15.6 | 301 | 4/12/2025 | |
| 2025.14.6 | 287 | 4/5/2025 | |
| 2025.13.14 | 318 | 3/30/2025 | |
| 2025.13.13 | 300 | 3/30/2025 | |
| 2025.13.12 | 297 | 3/30/2025 | |
| 2025.13.11 | 298 | 3/30/2025 | |
| 2025.13.10 | 296 | 3/30/2025 | |
| 2025.13.9 | 379 | 3/30/2025 | |
| 2025.13.8 | 405 | 3/30/2025 | |
| 2025.13.7 | 411 | 3/30/2025 | |
| 2025.11.2 | 364 | 3/14/2025 | |
| 2025.10.4 | 496 | 3/6/2025 | |
| 2025.10.1 | 477 | 3/6/2025 | |
| 2025.7.10 | 408 | 2/16/2025 | |
| 2025.7.9 | 363 | 2/16/2025 | |
| 2025.7.8 | 369 | 2/15/2025 |