Services Registration & Lifetimes
How to configure and register BeepService with Microsoft Dependency Injection for desktop, web, Blazor, and CLI applications.
TheTechIdea.Beep.Container.Services — DataManagementEngineStandard/Services/.
Overview
BeepService is the top-level container that wires together all core BeepDM components
(IDMEEditor, IConfigEditor, IAssemblyHandler, etc.) and exposes them
through a single IBeepService interface suitable for dependency injection.
AddBeepFor* platform shortcuts are not implemented.
Large parts of this page describe a platform-shortcut layer —
AddBeepForDesktop, AddBeepForWeb, AddBeepForBlazorServer,
AddBeepForBlazorWasm, AddBeepForMaui — together with
DesktopBeepOptions, WebBeepOptions and BlazorBeepOptions.
None of these exist in the current codebase. They appear only inside commented-out
sketches under DataManagementEngineStandard/Services/Examples/. Treat every
AddBeepFor* sample below as a proposed API, not a working one — it will not compile.
What the platform files (BeepServiceExtensions.Desktop/Web/Blazor/Maui.cs)
actually contain is the logging and audit preset pairs
(AddBeepLoggingForDesktop / AddBeepAuditForDesktop, and the Web, Blazor and MAUI
equivalents). Those are real — see
BeepService → Service Extensions.
For registration today, use the fluent builder or the options delegate, and set the lifetime explicitly
with AsSingleton() / AsScoped():
// Desktop equivalent of the proposed AddBeepForDesktop()
IBeepService beep = services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory)
.WithAppRepo("MyApp")
.WithConfigType(BeepConfigType.Application)
.WithMapping()
.WithAssemblyLoading()
.AsSingleton() // .AsScoped() for web / Blazor Server
.Build();
// Optional, and genuinely available:
services.AddBeepLoggingForDesktop("MyApp");
services.AddBeepAuditForDesktop("MyApp");
The services layer provides these registration styles:
| Style | API | Status | Best for |
|---|---|---|---|
| Fluent builder | AddBeepServices().WithDirectory(…).AsSingleton().Build() | ✅ Available | IntelliSense-driven, method-chained setup — recommended |
| Options pattern | AddBeepServices(Action<BeepServiceOptions>) | ✅ Available | Fine-grained cross-platform control |
| Legacy simple | Register(services, path, name, configType) | ✅ Available | Backward compatibility only |
| Direct | new BeepService(services) + Configure(…) | ✅ Available | No DI container / full manual control |
| Platform shortcuts | AddBeepForDesktop, AddBeepForWeb, AddBeepForBlazorServer, AddBeepForBlazorWasm | ❌ Not implemented | Proposed only — see the notice above |
Files in this module
| File | Purpose |
|---|---|
BeepService.cs | Core IBeepService implementation |
RegisterBeepinServiceCollection.cs | Core DI registration, fluent builder, options, validation exceptions |
BeepServiceExtensions.Desktop.cs | AddBeepLoggingForDesktop, AddBeepAuditForDesktop |
BeepServiceExtensions.Web.cs | AddBeepLoggingForWeb, AddBeepAuditForWeb |
BeepServiceExtensions.Blazor.cs | AddBeepLoggingForBlazor, AddBeepAuditForBlazor (require an IIndexedDbBridge) |
BeepServiceExtensions.Maui.cs | AddBeepLoggingForMaui, AddBeepAuditForMaui (require an app-data directory provider) |
BeepServiceExtensions.Logging.cs | AddBeepLogging + LoggingPipelineKey |
BeepServiceExtensions.Audit.cs | AddBeepAudit + AuditPipelineKey |
BeepServiceExtensions.AddinDiscovery.cs | AddBeepViews, AddBeepViewModels, discovery hook events |
BeepServiceExtensions.DataSources.cs | AddDataSourceDriver overloads |
BeepServiceExtensions.Retention.cs | AddBeepBudgetEnforcer, AddBeepRetentionSweeper |
BeepServiceExtensions.Schema.cs | AddBeepSchemaManager |
BeepServiceExtensions.EntityDiscovery.cs | AddBeepEntityDiscovery |
BeepServiceExtensions.Diagnostics.cs | internal — diagnostics attachment and metrics snapshot |
BeepConnectionRepository.cs | Scope/profile-aware connection catalog wired in by Configure() |
IConnectionStorageProvider.cs, JsonConnectionStorageProvider.cs | Pluggable connection storage backend |
ConnectionHealthMonitor.cs | Opt-in connection health polling and reconnect |
EnvironmentService.cs | Platform folder creation and mapping helpers |
ServiceCollectionExtensions.cs | Low-level JsonLoader / DMEEditor registrations |
ServiceHelper.cs | Static service-locator helper (use sparingly) |
BeepService
BeepService implements IBeepService and IDisposable.
It creates and owns all core BeepDM component instances during Configure().
Properties
| Property | Type | Description |
|---|---|---|
DMEEditor | IDMEEditor | Central data management orchestrator |
Config_editor | IConfigEditor | Connection and mapping configuration |
lg | IDMLogger | Logger instance |
util | IUtil | Utility helpers |
Erinfo | IErrorsInfo | Error tracking object |
jsonLoader | IJsonLoader | JSON serialisation service |
LLoader | IAssemblyHandler | Plugin / assembly loader |
Services | IServiceCollection | DI container (null if instantiated directly) |
AppRepoName | string | Container / application repository name |
ConfigureationType | BeepConfigType | Active configuration mode |
BeepDirectory | string | Root directory for Beep data files |
Containername | string | Obsolete Use AppRepoName |
Configure()
Initialises all components. Called automatically by the DI registration helpers or manually for direct instantiation.
// Direct instantiation (no DI):
var beep = new BeepService();
beep.Configure(
directorypath: AppContext.BaseDirectory,
containername: "MyApp",
configType: BeepConfigType.DataConnector,
AddasSingleton: false
);
Initialisation order inside Configure():
- Sets
AppRepoName,ConfigureationType,BeepDirectory - Creates
ErrorsInfo,DMLogger,JsonLoader - Creates
ConfigEditor(reads JSON configs from{BeepDirectory}/Beep) - Creates
Util,AssemblyHandler,DMEEditor - Optionally registers all instances into
IServiceCollection(singleton or scoped) - Calls
LoadConfigurations()— loads data-source configs, mappings
LoadServicesScoped() / LoadServicesSingleton()
// Called automatically by Configure(); exposed for advanced scenarios
beep.LoadServicesSingleton(); // registers IDMLogger, IConfigEditor, IDMEEditor, IUtil, IJsonLoader, IAssemblyHandler
beep.LoadServicesScoped(); // registers same interfaces using AddKeyedScoped
BeepServiceOptions
The canonical options object used by all registration helpers.
| Property | Type | Default | Description |
|---|---|---|---|
DirectoryPath | string | AppContext.BaseDirectory | Root directory for Beep data storage |
AppRepoName | string | "BeepApp" | Logical application / container name |
ConfigType | BeepConfigType | Application | Configuration storage mode |
ServiceLifetime | ServiceLifetime | Singleton | DI lifetime (overridden by platform helpers) |
EnableAutoMapping | bool | true | Creates type mappings at startup |
EnableAssemblyLoading | bool | true | Scans and loads driver/addin assemblies |
InitializationTimeout | TimeSpan | 5 min | Maximum wait for async initialization |
EnableConfigurationValidation | bool | true | Validates options before startup |
AdditionalProperties | Dictionary<string,object> | empty | Platform-specific extension values |
Validation Exceptions
| Exception | When thrown | Key properties |
|---|---|---|
BeepServiceValidationException | Configuration validation fails | PropertyName, InvalidValue |
BeepServiceStateException | Runtime state is invalid | ComponentName |
Desktop Registration
AddBeepForDesktop, DesktopBeepOptions) is a design sketch that does not exist in
the codebase and will not compile. For a desktop app today, use
services.AddBeepServices().WithDirectory(…).WithAppRepo(…).AsSingleton().Build().
The proposal was for AddBeepForDesktop to cover WinForms, WPF, and any long-running desktop
process, always registering as Singleton.
DesktopBeepOptions
| Property | Default | Description |
|---|---|---|
DirectoryPath | AppContext.BaseDirectory | Root data directory |
AppRepoName | "DesktopApp" | Container name |
ConfigType | Application | Config mode |
EnableAutoMapping | true | Maps at startup |
EnableAssemblyLoading | true | Scans plugins |
EnableProgressReporting | true | Enables UI progress hooks |
EnableDesignTimeSupport | true | Supports VS designers |
AutoInitializeForms | false | Auto-init forms on startup |
InitializationTimeout | 5 min | Max startup wait |
Registration
// In Program.cs (WinForms / WPF with IHost):
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddBeepForDesktop(opts =>
{
opts.DirectoryPath = AppContext.BaseDirectory;
opts.AppRepoName = "MyDesktopApp";
opts.EnableProgressReporting = true;
opts.EnableAutoMapping = true;
opts.EnableAssemblyLoading = true;
});
})
.Build();
// Resolve after host is built:
var beepService = host.Services.GetRequiredService<IBeepService>();
With Progress Reporting
var progress = new Progress<PassedArgs>(args =>
{
Console.WriteLine($"[{args.EventType}] {args.Messege}");
});
// If your desktop extension surfaces a UseBeepForDesktop method:
var beepService = host.UseBeepForDesktop(progress);
ServiceLifetime.Singleton — the lifetime in BeepServiceOptions
is overridden automatically by DesktopBeepOptions.ToBeepServiceOptions().
Web / ASP.NET Core Registration
AddBeepForWeb,
WebBeepOptions and the app.UseBeepForWeb() middleware do not exist in the
codebase. There is no Beep-supplied ASP.NET Core middleware at all. For a web app today, use
builder.Services.AddBeepServices().WithDirectory(…).WithAppRepo(…).AsScoped().Build().
The proposal was for AddBeepForWeb to cover ASP.NET Core Web API and MVC applications,
always registering as Scoped (one instance per HTTP request).
WebBeepOptions
| Property | Default | Description |
|---|---|---|
DirectoryPath | {BaseDir}/Beep | Root data directory |
AppRepoName | "WebApp" | Container name |
EnableAutoMapping | true | Maps at startup |
EnableAssemblyLoading | true | Scans plugins |
EnableRequestIsolation | true | Isolates state per HTTP request |
EnableConnectionPooling | true | Reuses connections across requests |
EnableApiDiscovery | false | Auto-discovers BeepService API endpoints |
InitializationTimeout | 5 min | Max startup wait |
Registration & Middleware
// Program.cs — options pattern
builder.Services.AddBeepForWeb(opts =>
{
opts.DirectoryPath = Path.Combine(builder.Environment.ContentRootPath, "Beep");
opts.AppRepoName = "MyWebApi";
opts.EnableConnectionPooling = true;
opts.EnableRequestIsolation = true;
});
var app = builder.Build();
app.UseBeepForWeb(); // Registers connection cleanup middleware
app.MapControllers();
app.Run();
Fluent Builder (Web)
builder.Services.AddBeepForWeb()
.InDirectory(Path.Combine(basePath, "Beep"))
.WithAppRepo("MyWebApi")
.WithConnectionPooling()
.WithRequestIsolation()
.WithApiDiscovery()
.WithMapping()
.Build();
Controller Injection Example
[ApiController]
[Route("api/[controller]")]
public class DataSourceController : ControllerBase
{
private readonly IBeepService _beep;
public DataSourceController(IBeepService beep) => _beep = beep;
[HttpGet("list")]
public IActionResult GetDataSources()
{
var sources = _beep.DMEEditor.DataSources
.Select(ds => new { ds.DatasourceName, Type = ds.DatasourceType.ToString() });
return Ok(sources);
}
}
Blazor Registration
AddBeepForBlazorServer,
AddBeepForBlazorWasm and BlazorBeepOptions do not exist in the codebase.
Use AddBeepServices() with AsScoped() for Blazor Server and
AsSingleton() for Blazor WebAssembly.
What is real in
BeepServiceExtensions.Blazor.cs is the logging/audit pair
AddBeepLoggingForBlazor(IIndexedDbBridge bridge, …) and
AddBeepAuditForBlazor(IIndexedDbBridge bridge, …) — both require an
IIndexedDbBridge for browser-side storage.
The proposal was for two separate extension methods covering the two Blazor hosting models.
BlazorBeepOptions
| Property | Default | Description |
|---|---|---|
DirectoryPath | {BaseDir}/Beep | Root data directory |
AppRepoName | "BlazorApp" | Container name |
ServiceLifetime | Set per method | Scoped (Server) or Singleton (WASM) |
EnableSignalRProgress | false | Real-time progress via SignalR (Server) |
UseBrowserStorage | false | Browser localStorage/sessionStorage (WASM) |
EnableCircuitHandlers | false | Circuit lifecycle hooks (Server) |
EnableAutoMapping | true | Maps at startup |
EnableAssemblyLoading | true | Scans plugins |
Blazor Server
// Program.cs — Blazor Server
builder.Services.AddBeepForBlazorServer(opts =>
{
opts.DirectoryPath = Path.Combine(builder.Environment.ContentRootPath, "Beep");
opts.AppRepoName = "MyBlazorServerApp";
opts.EnableSignalRProgress = true; // real-time progress via SignalR
opts.EnableCircuitHandlers = true; // cleanup on circuit disconnect
});
// Lifetime = Scoped (one per Blazor circuit)
Blazor WebAssembly
// Program.cs — Blazor WASM
builder.Services.AddBeepForBlazorWasm(opts =>
{
opts.DirectoryPath = "Beep"; // browser virtual path
opts.AppRepoName = "MyBlazorWasmApp";
opts.UseBrowserStorage = true; // persist config in localStorage
});
// Lifetime = Singleton (WASM has single user per process)
Blazor Component Usage
@inject IBeepService BeepService
@inject IJSRuntime JSRuntime
@code {
private List<string> dataSources = new();
protected override async Task OnInitializedAsync()
{
var ds = BeepService.DMEEditor.GetDataSource("mydb");
if (ds != null)
{
var entities = await Task.Run(() => ds.GetEntities("", new List<ReportFilter>()));
dataSources = entities.Select(e => e.EntityName).ToList();
}
}
}
Fluent Builder API
AddBeepServices() (no arguments) returns an IBeepServiceBuilder for method-chained configuration.
This provides the best IntelliSense experience and is platform-agnostic.
IBeepServiceBuilder Methods
| Method | Description |
|---|---|
WithDirectory(path) | Sets DirectoryPath |
WithAppRepo(name) | Sets AppRepoName |
WithConfigType(type) | Sets ConfigType |
WithMapping(enable) | Enables/disables auto mapping |
WithAssemblyLoading(enable) | Enables/disables plugin scanning |
WithTimeout(timeSpan) | Sets initialization timeout |
WithValidation(enable) | Enables/disables startup validation |
WithProperty(key, value) | Adds an entry to AdditionalProperties |
AsSingleton() | Registers as Singleton lifecycle |
AsScoped() | Registers as Scoped lifecycle |
AsTransient() | Registers as Transient lifecycle |
Build() | Completes registration and returns IBeepService |
Usage
// Desktop (singleton)
services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory)
.WithAppRepo("MyApp")
.WithConfigType(BeepConfigType.Application)
.WithMapping()
.WithAssemblyLoading()
.AsSingleton()
.Build();
// Web (scoped)
services.AddBeepServices()
.WithDirectory(Path.Combine(basePath, "Beep"))
.WithAppRepo("MyWebApi")
.WithProperty("EnableConnectionPooling", true)
.AsScoped()
.Build();
Options Pattern (alternative)
IBeepService beep = services.AddBeepServices(opts =>
{
opts.DirectoryPath = AppContext.BaseDirectory;
opts.AppRepoName = "MyApp";
opts.ConfigType = BeepConfigType.DataConnector;
opts.ServiceLifetime = ServiceLifetime.Singleton;
opts.EnableAutoMapping = true;
opts.EnableAssemblyLoading = true;
});
Legacy Registration API
Register() is preserved for backward compatibility. Prefer the platform-specific helpers for new code.
// Backward-compatible simple registration
IBeepService beep = services.Register(
directoryPath: AppContext.BaseDirectory,
containerName: "MyApp",
configType: BeepConfigType.DataConnector,
addAsSingleton: true
);
EnvironmentService
EnvironmentService is a static helper that resolves platform-appropriate data folder paths
and populates BeepDM mapping configurations. It is called internally by BeepService.Configure()
but can also be used directly.
Folder Creation
// Create the root Beep folder in a platform-appropriate location:
// Windows: %APPDATA%\TheTechIdea\Beep (or AppContext.BaseDirectory\TheTechIdea\Beep)
// Linux/macOS: ~/.local/share/TheTechIdea/Beep
string mainFolder = EnvironmentService.CreateMainFolder();
// Create a named application repository sub-folder:
string appFolder = EnvironmentService.CreateAppRepofolder("MyApp");
// Extension form — callable on an IDMEEditor instance:
string path = dmeEditor.CreateMainFolder();
Beep Mapping Setup
// Registers all connection configs, datasource mappings, and query configs for an editor:
dmeEditor.CreateBeepMapping();
EnvironmentService.BeepDataPath and AppRepoDataPath are static read-only properties
that cache the last created folder paths. Useful for diagnostics.
ServiceCollectionExtensions
Low-level IServiceCollection extensions for registering individual BeepDM components.
JsonLoader
// Singleton (default for long-lived apps)
services.AddJsonLoader();
// Scoped (per-request in web apps)
services.AddJsonLoaderScoped();
// Transient (new instance each time)
services.AddJsonLoaderTransient();
DMEEditor
// Register as singleton with existing handler + logger instances
services.AddDMEEditor(assemblyHandler, logger);
AddBeepServices() over these low-level methods.
These extensions are intended for scenarios where you need granular control of individual component lifetimes.
ServiceHelper
ServiceHelper is a static service-locator that wraps a cached IServiceProvider.
Use it sparingly — prefer constructor injection wherever possible.
// Typically called once in Program.cs / App.xaml.cs after building the host:
ServiceHelper.Initialize(host.Services);
// Resolve a service anywhere, without constructor injection:
var beep = ServiceHelper.GetService<IBeepService>();
var editor = ServiceHelper.GetService<IDMEEditor>();
GetService before Initialize — it will throw a
NullReferenceException. Initialize as early as possible in the application lifecycle.
Lifetime Selection Guide
| Application type | Recommended lifetime | Registration method |
|---|---|---|
| WinForms / WPF desktop | Singleton | AddBeepServices().AsSingleton().Build() |
| Console / CLI | Singleton | AddBeepServices().AsSingleton().Build() |
| ASP.NET Core Web API / MVC | Scoped | AddBeepServices().AsScoped().Build() |
| Blazor Server | Scoped | AddBeepServices().AsScoped().Build() |
| Blazor WebAssembly | Singleton | AddBeepServices().AsSingleton().Build() |
| Azure Functions (isolated) | Scoped | AddBeepServices().AsScoped().Build() |
| Background / Worker services | Singleton | AddBeepServices().AsSingleton().Build() |
IBeepService into a Singleton — this creates a captive dependency.
If a singleton component needs BeepService, register BeepService as Singleton or use IServiceScopeFactory.
BeepConfigType Values
| Value | Typical use |
|---|---|
Application | Full application with UI, forms, and complete driver set |
DataConnector | Data-only mode — connections and mappings, no UI components. Used by design-time bootstrap. |
Container | Container/host scenario |
DataManagementModelsStandard/Enums/Enums.cs as
Application, DataConnector, Container. Earlier revisions of this page listed a
Server member, and other pages have listed Plugin and DesignTime —
none of those exist.
End-to-End Examples
AddBeepFor* API and will not compile.
Substitute the real builder, keeping the lifetime each example implies:
// Example 1 (WinForms) and Example 4 (Blazor WASM) -> Singleton
services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory).WithAppRepo("MyApp")
.WithConfigType(BeepConfigType.Application)
.WithMapping().WithAssemblyLoading()
.AsSingleton().Build();
// Example 2 (Web API) and Example 3 (Blazor Server) -> Scoped
builder.Services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory).WithAppRepo("MyApp")
.WithConfigType(BeepConfigType.Application)
.AsScoped().Build();
Example 5 (direct instantiation) and Example 6 (fluent builder) are accurate as written.
Example 1 — WinForms with IHost
// Program.cs
[STAThread]
static void Main()
{
var host = Host.CreateDefaultBuilder()
.ConfigureServices((ctx, services) =>
{
services.AddBeepForDesktop(opts =>
{
opts.DirectoryPath = AppContext.BaseDirectory;
opts.AppRepoName = "MyDesktopApp";
opts.EnableProgressReporting = true;
});
services.AddSingleton<MainForm>();
})
.Build();
ServiceHelper.Initialize(host.Services);
var beepService = host.Services.GetRequiredService<IBeepService>();
Application.Run(host.Services.GetRequiredService<MainForm>());
}
Example 2 — ASP.NET Core Web API
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBeepForWeb(opts =>
{
opts.DirectoryPath = Path.Combine(builder.Environment.ContentRootPath, "Beep");
opts.AppRepoName = "MyWebApi";
opts.EnableConnectionPooling = true;
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseBeepForWeb();
app.MapControllers();
app.Run();
Example 3 — Blazor Server
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
builder.Services.AddBeepForBlazorServer(opts =>
{
opts.AppRepoName = "MyBlazorApp";
opts.EnableSignalRProgress = true;
opts.EnableCircuitHandlers = true;
});
var app = builder.Build();
app.MapRazorComponents<App>().AddInteractiveServerRenderMode();
app.Run();
Example 4 — Blazor WebAssembly
// Program.cs
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddBeepForBlazorWasm(opts =>
{
opts.AppRepoName = "MyBlazorWasmApp";
opts.UseBrowserStorage = true;
});
await builder.Build().RunAsync();
Example 5 — Direct Instantiation (No DI)
// Useful for unit tests, console scripts, or legacy code
var beep = new BeepService();
beep.Configure(
directorypath: Path.Combine(Path.GetTempPath(), "BeepTest"),
containername: "TestContainer",
configType: BeepConfigType.DataConnector,
AddasSingleton: false
);
var ds = beep.DMEEditor.GetDataSource("northwind");
ds.Openconnection();
Example 6 — Fluent Builder (Generic / CLI)
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((ctx, services) =>
{
services.AddBeepServices()
.WithDirectory(AppContext.BaseDirectory)
.WithAppRepo("BeepShell")
.WithConfigType(BeepConfigType.Application)
.WithAssemblyLoading()
.WithMapping()
.AsSingleton()
.Build();
})
.Build();
var beep = host.Services.GetRequiredService<IBeepService>();