Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .docfx/Dockerfile.docfx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG NGINX_VERSION=1.31.0-alpine
ARG NGINX_VERSION=1.31.2-alpine

FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base
RUN rm -rf /usr/share/nginx/html/*
Expand Down
10 changes: 7 additions & 3 deletions .docfx/api/namespaces/Codebelt.Bootstrapper.Console.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
uid: Codebelt.Bootstrapper.Console
summary: *content
---
The `Codebelt.Bootstrapper.Console` namespace offers an implementation optimized for console applications that is managed by its host.
The `Codebelt.Bootstrapper.Console` namespace delivers the console-specific implementation of the Codebelt bootstrapper, including `ConsoleProgram<TStartup>`/`ConsoleStartup` for the conventional Program/Startup pair and `MinimalConsoleProgram` for the minimal-host model.

Use it when the host is a console application — a long-running daemon, a cron-style job, or a CLI process — and you want the `BootstrapperLifetime` callbacks (`OnApplicationStartedCallback`, `OnApplicationStoppingCallback`, `OnApplicationStoppedCallback`) to surface in your `Startup` so you can log and tear down cleanly. The minimal variant reflects over the entry assembly to discover a concrete `MinimalConsoleProgram` type, so the project keeps a clean `Program.cs` while still hosting a real application model.

If you are starting a new console application, start with `MinimalConsoleProgram` and its `CreateHostBuilder` helper — it composes `UseBootstrapperLifetime`, `UseBootstrapperEnvironmentDefaults`, `UseBootstrapperProgram`, and `UseMinimalConsoleProgram` in one call. If you are keeping the conventional `Program.cs`/`Startup.cs` split, start with `ConsoleProgram<TStartup>` and pair it with `ConsoleStartup` to register services and override `RunAsync`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Methods
### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|HostApplicationBuilder|⬇️|`UseBootstrapperProgram`, `UseMinimalConsoleProgram`|
|IHostBuilder|⬇️|`UseConsoleStartup`|
|IHostBuilder|⬇️|`UseConsoleStartup<TStartup>`|
11 changes: 8 additions & 3 deletions .docfx/api/namespaces/Codebelt.Bootstrapper.Web.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
uid: Codebelt.Bootstrapper.Web
summary: *content
---
The `Codebelt.Bootstrapper.Web` namespace offers an implementation optimized for web applications that is managed by its host.
The `Codebelt.Bootstrapper.Web` namespace is the web-specific implementation of the Codebelt bootstrapper. It adds `WebProgram<TStartup>`/`WebStartup` for the conventional ASP.NET Core Program/Startup pair and `MinimalWebProgram` for the minimal-host model.

Use it when the host is an ASP.NET Core web application — WebAPI, webapp, or MVC — and you want the same `BootstrapperLifetime` callbacks that console and worker applications use, applied to the web request pipeline. `WebStartup.ConfigurePipeline` is the entry point for the conventional pair and is wired up automatically by `WebHostBuilderExtensions.UseStartup<TStartup>` through the trivial `Configure` shim.

If you are starting a new web application, start with `MinimalWebProgram` and its `CreateHostBuilder` helper, then call `hb.UseBootstrapperLifetime()` to keep the lifetime consistent with the rest of the Codebelt family. If you are keeping the conventional Program/Startup split, start with `WebProgram<TStartup>` and pair it with `WebStartup` to define your service registration and request pipeline.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Methods
### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|WebApplicationBuilder|⬇️|`UseBootstrapperLifetime`|
|WebApplicationBuilder|⬇️|`UseBootstrapperLifetime`, `UseBootstrapperEnvironmentDefaults`|
|IHostBuilder|⬇️|`UseBootstrapperStartup<TStartup>`, `UseBootstrapperEnvironmentDefaults<TStartup>`|
6 changes: 5 additions & 1 deletion .docfx/api/namespaces/Codebelt.Bootstrapper.Worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
uid: Codebelt.Bootstrapper.Worker
summary: *content
---
The `Codebelt.Bootstrapper.Worker` namespace offers an implementation optimized for worker applications that is managed by its host.
If you build a .NET worker service and want the same lifetime callbacks and the same conventional Program.cs/Startup.cs split that the rest of the Codebelt family uses, the `Codebelt.Bootstrapper.Worker` namespace is your starting point. It provides `WorkerProgram<TStartup>` and `WorkerStartup` for the conventional Program/Startup pair, and `MinimalWorkerProgram` for the minimal-host model, both wired against `BootstrapperLifetime` and the shared `UseBootstrapperEnvironmentDefaults` for local-development user secrets.

Choose this namespace when the host is a `BackgroundService`, a long-running queue consumer, or any other `IHostedService` host that should react to startup and shutdown callbacks through `IHostLifetimeEvents`. The worker flavor is intentionally lightweight because worker hosts are almost always `Host.CreateApplicationBuilder` or `Host.CreateDefaultBuilder` based.

If you are starting a new worker service, start with `MinimalWorkerProgram` and its `CreateHostBuilder` helper — it composes `UseBootstrapperLifetime` and `UseBootstrapperEnvironmentDefaults` so a hosted service can react to lifetime events. If you are keeping the conventional Program/Startup split, start with `WorkerProgram<TStartup>` and pair it with `WorkerStartup` to register the worker's services.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
13 changes: 8 additions & 5 deletions .docfx/api/namespaces/Codebelt.Bootstrapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
uid: Codebelt.Bootstrapper
summary: *content
---
The `Codebelt.Bootstrapper` namespace offers core types of this lightweight boostrapper framework optimized for console applicationss, providing a uniform and consistent implementation of console-, worker-, web-, mvc-, webapp- and webapi-project types.
If you want a single .NET host that listens to SIGTERM/Ctrl+C, exposes a conventional Program.cs/Startup.cs split, and applies the same lifetime and environment defaults across console, web, and worker projects, the `Codebelt.Bootstrapper` namespace is the cross-cutting layer to start from. The namespace defines `BootstrapperLifetime` (which complements the default `Microsoft.Extensions.Hosting.Internal.ConsoleLifetime`), a `StartupRoot` partner for the conventional Program/Startup pair, and the shared `UseBootstrapperLifetime` / `UseBootstrapperStartup` / `UseBootstrapperEnvironmentDefaults` extension methods that the rest of the family (`Codebelt.Bootstrapper.Console`, `Codebelt.Bootstrapper.Web`, and `Codebelt.Bootstrapper.Worker`) compose on top of.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
Choose this surface when you need a uniform bootstrap regardless of project type, or when a console/worker/web project should share the same lifetime callbacks and the same conventional startup shape. If you are on the minimal-host model, start with `UseBootstrapperLifetime` on `IHostApplicationBuilder` to install `BootstrapperLifetime` together with `IHostLifetimeEvents` so a hosted service can react to startup and shutdown. If you are on the conventional Program/Startup pair, start with `UseBootstrapperStartup<TStartup>` on `IHostBuilder` to wire a `StartupRoot` partner into the service collection. For local-development user secrets, reach for `UseBootstrapperEnvironmentDefaults` (or its `TStartup` overload) so secrets are added to configuration automatically.

### Extension Methods
[!INCLUDE [availability-default](../../includes/availability-default.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|HostApplicationBuilder|⬇️|`UseBootstrapperLifetime`|
|IHostBuilder|⬇️|`UseBootstrapperLifetime`, `UseBootstrapperStartup`|
|HostApplicationBuilder|⬇️|`UseBootstrapperLifetime`, `UseBootstrapperEnvironmentDefaults`|
|IHostBuilder|⬇️|`UseBootstrapperLifetime`, `UseBootstrapperStartup<TStartup>`, `UseBootstrapperEnvironmentDefaults<TStartup>`|
|IHostedService|⬇️|`WaitForApplicationStartedAnnouncementAsync`|
|IDecorator<ILogger>|⬇️|`RunAsyncStarted`, `RunAsyncPrematureEnd`, `RunAsyncCompleted`, `UnableToActivateInstance`, `FatalErrorActivating`|
31 changes: 31 additions & 0 deletions .docfx/api/types/Codebelt.Bootstrapper.BootstrapperLifetime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
uid: Codebelt.Bootstrapper.BootstrapperLifetime
example:
- *content
---
The following example shows how to resolve `BootstrapperLifetime` from the host's service container, attach a callback to the application-stopped event, and confirm the lifetime is registered after the host starts. The `BootstrapperLifetime` replaces the default `Microsoft.Extensions.Hosting.Internal.ConsoleLifetime` so that consumers can subscribe to the same `IHostLifetimeEvents` surface area used by hosted services.

```csharp
using System;
using Codebelt.Bootstrapper;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace BootstrapperLifetimeDemo;

public static class Program
{
public static void Main()
{
var builder = Host.CreateApplicationBuilder();
builder.UseBootstrapperLifetime();
var host = builder.Build();
host.Start();

var lifetime = (BootstrapperLifetime)host.Services.GetRequiredService<IHostLifetime>();
lifetime.OnApplicationStoppedCallback = () => Console.WriteLine("Stopped.");

host.StopAsync().GetAwaiter().GetResult();
}
}
```
44 changes: 44 additions & 0 deletions .docfx/api/types/Codebelt.Bootstrapper.BootstrapperLogMessages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
uid: Codebelt.Bootstrapper.BootstrapperLogMessages
example:
- *content
---
The static `BootstrapperLogMessages` class is the host's source of truth for the four lifecycle events that `ConsoleHostedService<TStartup>` and `MinimalConsoleHostedService` log through `Decorator.EncloseToExpose(logger, false)`: `RunAsyncStarted` when the run loop begins, `RunAsyncPrematureEnd` when the host stops before the run finishes, `RunAsyncCompleted` when the run finishes cleanly, and `FatalErrorActivating` when the run loop's `catch` block sees an exception. The companion `UnableToActivateInstance` extension surfaces a warning when the bootstrapper could not resolve a startup or program type. To use them from your own `ConsoleStartup` or `MinimalConsoleProgram`, build an `ILogger<T>` through your normal `ServiceCollection` configuration and wrap it with `Decorator.EncloseToExpose(logger, false)`; the resulting `IDecorator<ILogger>` exposes all five extensions through receiver-style calls. The example below wires a console logger, demonstrates the run-loop happy path, exercises the failure path, and shows the startup-resolution warning so every extension in this class is invoked in a single coherent workflow.

```csharp
using System;
using Codebelt.Bootstrapper;
using Cuemon;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace BootstrapperLogMessagesDemo;

public class BootstrapperLogMessagesDemoHost
{
public void Run()
{
using var services = new ServiceCollection()
.AddLogging(builder => builder.AddConsole())
.BuildServiceProvider();

var logger = services.GetRequiredService<ILogger<BootstrapperLogMessagesDemoHost>>();
var decorated = Decorator.EncloseToExpose(logger, false);

decorated.RunAsyncStarted();

try
{
throw new InvalidOperationException("Boom");
}
catch (Exception ex)
{
decorated.FatalErrorActivating(typeof(BootstrapperLogMessagesDemoHost).FullName!, ex);
}

decorated.UnableToActivateInstance(typeof(BootstrapperLogMessagesDemoHost).FullName!);
decorated.RunAsyncPrematureEnd();
decorated.RunAsyncCompleted();
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
uid: Codebelt.Bootstrapper.Console.ConsoleHostedService`1
example:
- *content
---
The following example shows how `ConsoleHostedService<TStartup>` is registered by `UseConsoleStartup<TStartup>` on the conventional `IHostBuilder`, and how the hosted service itself can be resolved from the host's service collection. When the host starts, the service logs a `RunAsync started.` message through `BootstrapperLogMessages`, runs the `TStartup.RunAsync` task, and then calls `IHostApplicationLifetime.StopApplication` to begin a graceful shutdown.

```csharp
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Codebelt.Bootstrapper.Console;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ConsoleHostedServiceDemo;

public class MyStartup : ConsoleStartup
{
public MyStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment)
{
}

public override void ConfigureServices(IServiceCollection services)
{
}

public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

public static class Program
{
public static void Main()
{
var host = Host.CreateDefaultBuilder()
.UseConsoleStartup<MyStartup>()
.Build();

var hosted = host.Services.GetServices<IHostedService>();
var consoleHosted = hosted.OfType<ConsoleHostedService<MyStartup>>().Single();
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
uid: Codebelt.Bootstrapper.Console.HostApplicationBuilderExtensions
example:
- *content
---
The following example shows how to compose `UseBootstrapperProgram` and `UseMinimalConsoleProgram` on a `HostApplicationBuilder` to wire a `MinimalConsoleProgram` implementation into the host. The `ProgramFactory` then discovers the derived `MinimalConsoleProgram` in the entry assembly and the `MinimalConsoleHostedService` runs its `RunAsync` once the host is fully started.

```csharp
using System;
using System.Threading;
using System.Threading.Tasks;
using Codebelt.Bootstrapper.Console;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace MinimalConsoleHostDemo;

public class MyProgram : MinimalConsoleProgram
{
public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

public static class Program
{
public static void Main()
{
var builder = Host.CreateApplicationBuilder();
builder.UseBootstrapperProgram(typeof(MyProgram));
builder.UseMinimalConsoleProgram();

using var host = builder.Build();
var hosted = host.Services.GetServices<IHostedService>();
}
}
```

---
uid: Codebelt.Bootstrapper.Console.HostApplicationBuilderExtensions.UseBootstrapperProgram
example:
- *content
---
The following example shows how to call `UseBootstrapperProgram` on a `HostApplicationBuilder` to register a `ProgramFactory` that resolves a `MinimalConsoleProgram`-derived type at runtime.

```csharp
using System;
using System.Threading;
using System.Threading.Tasks;
using Codebelt.Bootstrapper.Console;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace UseBootstrapperProgramDemo;

public class MyProgram : MinimalConsoleProgram
{
public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

public static class Program
{
public static void Main()
{
var builder = Host.CreateApplicationBuilder();
builder.UseBootstrapperProgram(typeof(MyProgram));

using var host = builder.Build();
var factory = host.Services.GetRequiredService<IProgramFactory>();
}
}
```

---
uid: Codebelt.Bootstrapper.Console.HostApplicationBuilderExtensions.UseMinimalConsoleProgram
example:
- *content
---
The following example shows how to call `UseMinimalConsoleProgram` on a `HostApplicationBuilder` to register the `MinimalConsoleHostedService` so the run loop is driven from a single hosted service.

```csharp
using System;
using System.Threading;
using System.Threading.Tasks;
using Codebelt.Bootstrapper.Console;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace UseMinimalConsoleProgramDemo;

public class MyProgram : MinimalConsoleProgram
{
public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

public static class Program
{
public static void Main()
{
var builder = Host.CreateApplicationBuilder();
builder.UseBootstrapperProgram(typeof(MyProgram));
builder.UseMinimalConsoleProgram();

using var host = builder.Build();
var hosted = host.Services.GetServices<IHostedService>();
}
}
```
Loading
Loading