Web Framework
SaveApis.Framework.Web provides a ready-to-use ASP.NET Core application with structured logging, OpenTelemetry, FluentValidation, authentication/authorization via Zitadel, controller routing, and an OpenAPI/Scalar UI — all wired up through the Installer system.
Table of Contents
- Overview
- Entry Point
- Default Installers
- Custom Installers
- Enabling & Disabling Installers
- Configuration Reference
- Installer Sub-Pages
Overview
When to use: Use the Web Framework whenever you are building an HTTP API or web service.
What it provides out of the box:
- Structured console logging via Serilog
- OpenTelemetry traces, metrics, and logs exported via OTLP
- FluentValidation registered from your assembly
- ASP.NET Core Authentication & Authorization middleware
- Zitadel token introspection (JWT profile)
- Controller registration with
JsonStringEnumConverter - OpenAPI document generation (with Zitadel OAuth2 security scheme)
- Scalar API Reference UI
Key difference from other frameworks: The Web Framework uses WebApplicationBuilder / WebApplication internally and is the only framework that supports HTTP middleware pipeline configuration via ConfigureApplication.
Entry Point
Start the application from Program.cs:
using SaveApis.Framework;
using SaveApis.Framework.Web.Extensions;
await SaveApisApplication
.AsWeb(
args,
(app, installer) =>
{
app.Name = "My.Service";
app.Namespace = "My.Org";
installer.SetSoftwareAssembly(); // required for controller and validator scanning
}
)
.Build()
.RunAsync()
.ConfigureAwait(false);
The configure callback receives an ApplicationContext (app) and a WebInstallerContext (installer). Both are optional — the callback itself can be omitted.
Add your own installers before Build():
await SaveApisApplication
.AsWeb(args, (app, installer) => { ... })
.AddInstaller<MyInstaller>()
.Build()
.RunAsync();
Default Installers
The following installers are registered automatically when you call AsWeb(). They run in dependency order:
| # | Installer | Key | Default Enabled |
|---|---|---|---|
| 1 | LoggingInstaller |
Logging |
✅ |
| 2 | OpenTelemetryInstaller |
OpenTelemetry |
✅ |
| 3 | ValidationInstaller |
Validation |
✅ |
| 4 | AuthenticationInstaller |
Authentication |
✅ |
| 5 | AuthorizationInstaller |
Authorization |
✅ |
| 6 | ZitadelInstaller |
Zitadel |
✅ |
| 7 | ControllerInstaller |
Controller |
✅ |
| 8 | OpenApiInstaller |
OpenApi |
✅ |
| 9 | ScalarInstaller |
Scalar |
✅ |
LoggingInstaller
Key: Logging
Clears all default logging providers and installs Serilog with a formatted ANSI console sink.
Default minimum level: Information
Built-in overrides (always applied):
Microsoft.AspNetCore→WarningSystem.Net.Http→Warning
Configuration (section Logging):
| Key | Type | Default | Description |
|---|---|---|---|
Logging:Default |
LogEventLevel |
Information |
Global minimum log level |
Logging:Override:<source> |
LogEventLevel |
– | Per-source override, e.g. Logging:Override:MyNamespace |
Example (appsettings.json):
{
"Logging": {
"Default": "Debug",
"Override": {
"Microsoft.AspNetCore": "Warning"
}
}
}
OpenTelemetryInstaller
Key: OpenTelemetry
Registers OpenTelemetry SDK with logging, metrics, and tracing exported via OTLP. The resource is configured with SaveApisApplication.Name, SaveApisApplication.Namespace, and Environment.MachineName.
Instrumentation included:
- Metrics: .NET runtime, HttpClient, ASP.NET Core
- Tracing: HttpClient (with exception recording), ASP.NET Core (with exception recording, path filtering)
- Logging: OpenTelemetry log processor with formatted messages and scopes
Configuration (section OpenTelemetry):
| Key | Type | Default | Description |
|---|---|---|---|
OpenTelemetry:Endpoint |
Uri |
(required) | OTLP exporter endpoint |
OpenTelemetry:Protocol |
OtlpExportProtocol |
Grpc |
Grpc or HttpProtobuf |
OpenTelemetry:Logging:Enabled |
bool |
true |
Enable log export |
OpenTelemetry:Metrics:Enabled |
bool |
true |
Enable metrics export |
OpenTelemetry:Tracing:Enabled |
bool |
true |
Enable trace export |
OpenTelemetry:Tracing:IgnoredPaths |
string[] |
["/scalar", "/openapi"] |
Paths excluded from tracing |
ValidationInstaller
Key: Validation
Scans SoftwareAssembly and all additional assemblies from InstallerContext.Assemblies for FluentValidation IValidator<T> implementations and registers them in the DI container.
No configuration required.
AuthenticationInstaller
Key: Authentication
Registers ASP.NET Core Authentication services (builder.Services.AddAuthentication()) and adds the UseAuthentication() middleware to the pipeline.
This installer must run before AuthorizationInstaller, ZitadelInstaller, ControllerInstaller, OpenApiInstaller, and ScalarInstaller — all declared as Before dependencies.
No configuration required on its own; configure authentication schemes in additional installers (e.g. ZitadelInstaller).
AuthorizationInstaller
Key: Authorization
Registers ASP.NET Core Authorization services (builder.Services.AddAuthorization()) and adds the UseAuthorization() middleware.
Must run after AuthenticationInstaller and before ZitadelInstaller, ControllerInstaller, OpenApiInstaller, and ScalarInstaller.
No configuration required.
ZitadelInstaller
Key: Zitadel
Adds Zitadel token introspection as an authentication scheme. Only activates if Zitadel:JwtProfile is set — if the value is empty or missing, the installer is a no-op (no error).
Also registers a distributed memory cache used by the introspection middleware for caching tokens for 5 minutes.
Must run after AuthenticationInstaller and AuthorizationInstaller.
Configuration (section Zitadel):
| Key | Type | Required | Description |
|---|---|---|---|
Zitadel:Authority |
Uri |
Yes | Zitadel instance URL (e.g. https://auth.example.com/) |
Zitadel:JwtProfile |
string |
Yes | JSON string of the Zitadel service account JWT profile |
Zitadel:Scopes |
Dictionary<string, string> |
No | OAuth2 scopes shown in Scalar/OpenAPI UI |
Default scopes (used by OpenApiInstaller for the security scheme):
{
"openid": "OpenID Connect",
"profile": "Profile",
"email": "Email",
"urn:zitadel:iam:user:resourceowner": "Organization Name"
}
Tip: To disable Zitadel in development, use
installer.WithZitadel(false)in the configure callback. TheOpenApiInstallerandScalarInstallerwill automatically omit the security scheme.
ControllerInstaller
Key: Controller
Registers ASP.NET Core MVC controllers, adds all controller application parts from SoftwareAssembly and InstallerContext.Assemblies, configures JsonStringEnumConverter for all JSON serialization, and maps controllers with .RequireAuthorization() in the pipeline.
Must run after AuthenticationInstaller, AuthorizationInstaller, and ZitadelInstaller.
No configuration required.
OpenApiInstaller
Key: OpenApi
Generates an OpenAPI document using the built-in ASP.NET Core OpenAPI support and exposes it at /openapi/v1.json (anonymous access).
When Zitadel is enabled, automatically adds an OAuth2 Authorization Code security scheme to the document using the Zitadel:Authority and Zitadel:Scopes configuration values.
Must run after ControllerInstaller.
No additional configuration required.
ScalarInstaller
Key: Scalar
Mounts the Scalar API Reference UI (anonymous access). Configured with opinionated defaults:
- Dark mode, DeepSpace theme, Modern layout
- CSharp/HttpClient as the only shown client
- Download as JSON
- Test request button only visible in
Development - Persistent authentication (remembers token across page reloads)
- When Zitadel is enabled, pre-selects the
Zitadelsecurity scheme
Must run after OpenApiInstaller.
No configuration required.
Custom Installers
Inherit from BaseWebInstaller to create your own installer:
public class MyInstaller : BaseWebInstaller
{
public override string InstallerKey => "My";
// Optional: declare ordering constraints
public override IReadOnlyCollection<InstallerDependency> Dependencies =>
[
InstallerDependency.After<ValidationInstaller>(),
];
public override void ConfigureBuilder(
SaveApisWebApplicationBuilder builder,
WebInstallerContext context)
{
builder.Services.AddScoped<IMyService, MyService>();
}
public override void ConfigureApplication(
SaveApisWebApplication application,
WebInstallerContext context)
{
application.Use(app => app.UseMyMiddleware());
}
}
Register it in Program.cs:
await SaveApisApplication
.AsWeb(args, (app, installer) => { ... })
.AddInstaller<MyInstaller>()
.Build()
.RunAsync();
Reading configuration options:
public override void ConfigureBuilder(SaveApisWebApplicationBuilder builder, WebInstallerContext context)
{
var options = GetOption<MyOptions>(builder); // reads section "My" (= InstallerKey)
builder.Services.AddSingleton(options);
}
For the full installer API (lifecycle, dependencies, ShouldInstall, etc.) see the Base Framework documentation.
Enabling & Disabling Installers
Use the WebInstallerContext extension methods in the configure callback:
(app, installer) =>
{
installer.WithLogging(false); // disable Serilog
installer.WithOpenTelemetry(false); // disable OpenTelemetry
installer.WithValidation(false); // disable FluentValidation
installer.WithAuthentication(false); // disable Authentication middleware
installer.WithAuthorization(false); // disable Authorization middleware
installer.WithZitadel(false); // disable Zitadel introspection
installer.WithControllers(false); // disable controller registration
installer.WithOpenApi(false); // disable OpenAPI document
installer.WithScalar(false); // disable Scalar UI
}
All methods default to true (enable) and accept false to disable.
Configuration Reference
| Section | Key | Type | Default | Required |
|---|---|---|---|---|
Logging |
Default |
LogEventLevel |
Information |
No |
Logging |
Override:<source> |
LogEventLevel |
– | No |
OpenTelemetry |
Endpoint |
Uri |
– | Yes (if enabled) |
OpenTelemetry |
Protocol |
OtlpExportProtocol |
Grpc |
No |
OpenTelemetry |
Logging:Enabled |
bool |
true |
No |
OpenTelemetry |
Metrics:Enabled |
bool |
true |
No |
OpenTelemetry |
Tracing:Enabled |
bool |
true |
No |
OpenTelemetry |
Tracing:IgnoredPaths |
string[] |
["/scalar","/openapi"] |
No |
Zitadel |
Authority |
Uri |
– | Yes (if enabled) |
Zitadel |
JwtProfile |
string |
– | Yes (if enabled) |
Zitadel |
Scopes |
Dictionary<string,string> |
(see above) | No |
Installer Sub-Pages
Detailed documentation for each default installer, including full configuration reference (appsettings + environment variables) and context extension methods:
| Installer | Sub-Page |
|---|---|
LoggingInstaller |
logging/ |
OpenTelemetryInstaller |
opentelemetry/ |
ValidationInstaller |
validation/ |
AuthenticationInstaller |
authentication/ |
AuthorizationInstaller |
authorization/ |
ZitadelInstaller |
zitadel/ |
ControllerInstaller |
controller/ |
OpenApiInstaller |
openapi/ |
ScalarInstaller |
scalar/ |