AppBuilder
AppBuilder is a fluent entry point that replaces the usual Program.cs boilerplate. It composes a host (by default a WebApplication), lets you attach modular setup containers, registers startup gates, and gives you lifecycle hooks — all before returning an AppRunner you can RunAsync.
Quick start
using Servus.Application.Startup;
var app = AppBuilder
.Create()
.WithSetup<GrpcSetupContainer>()
.WithSetup<LoggingSetupContainer>()
.Build();
await app.RunAsync();AppBuilder.Create() uses WebApplication.CreateBuilder() by default. If you need a different host type (e.g. HostApplicationBuilder for a console worker), pass your own:
var app = AppBuilder
.Create(Host.CreateApplicationBuilder(args), b => b.Build())
.WithSetup<MyWorkerSetup>()
.Build();Attaching setup containers
WithSetup<T>() and WithSetup(instance) attach one or more Setup Containers. Each container implements one or more of the lifecycle interfaces (IServiceSetupContainer, IConfigurationSetupContainer, ILoggingSetupContainer, ApplicationSetupContainer) and AppBuilder calls them in the right order.
var app = AppBuilder
.Create()
.WithSetup<ConfigSetup>() // IConfigurationSetupContainer
.WithSetup<ServicesSetup>() // IServiceSetupContainer
.WithSetup<LoggingSetup>() // ILoggingSetupContainer
.WithSetup<MiddlewareSetup>() // ApplicationSetupContainer<WebApplication>
.Build();Containers are the split-and-compose unit of a Servus app. Keep each container focused on one concern — you reuse them across projects and in unit tests.
Startup gates
Block the app from starting until something outside is ready (a database, an upstream API, a license server, a file to appear). See Startup Gates for the full flow.
var app = AppBuilder
.Create()
.WithSetup<ServicesSetup>()
.WithStartupGate(async () => await db.CanConnectAsync())
.WithStartupGate<LicenseServerGate>()
.Build();
await app.RunAsync();Lifecycle hooks
Run code at the three standard hosting transitions:
var app = AppBuilder
.Create()
.WithSetup<ServicesSetup>()
.OnApplicationStarted(sp => sp.GetRequiredService<IMetrics>().MarkStart())
.OnApplicationStopping(() => Log.Information("Going down…"))
.OnApplicationStopped(() => Log.Information("Bye."))
.Build();Full API
public class AppBuilder
{
public static AppBuilder Create<T>(T builder, Func<T, IHost> createHost) where T : IHostApplicationBuilder;
public static AppBuilder Create();
public AppBuilder WithSetup<TContainer>() where TContainer : class, ISetupContainer, new();
public AppBuilder WithSetup(ISetupContainer container);
public AppBuilder WithStartupGate(Func<Task<bool>> gate);
public AppBuilder WithStartupGate<TGate>() where TGate : class, IStartupGate, new();
public AppBuilder WithStartupGate(IStartupGate gate);
public AppBuilder OnApplicationStarted(Action<IServiceProvider> started);
public AppBuilder OnApplicationStopping(Action stopping);
public AppBuilder OnApplicationStopped(Action stopped);
public AppRunner Build();
}
public partial class AppRunner
{
public Task RunAsync(CancellationToken token = default);
public Task StartAsync(CancellationToken token);
}