CasCap.Common.Hosting.AspNetCore
5.2.0
Prefix Reserved
dotnet add package CasCap.Common.Hosting.AspNetCore --version 5.2.0
NuGet\Install-Package CasCap.Common.Hosting.AspNetCore -Version 5.2.0
<PackageReference Include="CasCap.Common.Hosting.AspNetCore" Version="5.2.0" />
<PackageVersion Include="CasCap.Common.Hosting.AspNetCore" Version="5.2.0" />
<PackageReference Include="CasCap.Common.Hosting.AspNetCore" />
paket add CasCap.Common.Hosting.AspNetCore --version 5.2.0
#r "nuget: CasCap.Common.Hosting.AspNetCore, 5.2.0"
#:package CasCap.Common.Hosting.AspNetCore@5.2.0
#addin nuget:?package=CasCap.Common.Hosting.AspNetCore&version=5.2.0
#tool nuget:?package=CasCap.Common.Hosting.AspNetCore&version=5.2.0
CasCap.Common.Hosting.AspNetCore
ASP.NET Core hosting defaults for feature-gated controllers, Serilog logging, and OpenTelemetry metrics, traces, and logs.
Installation
dotnet add package CasCap.Common.Hosting.AspNetCore
Target frameworks: net10.0, net11.0
Usage
In an ASP.NET Core application, enable the controller features this host can serve:
using System;
using System.Collections.Generic;
using CasCap.Common.Abstractions;
using CasCap.Common.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
var enabledFeatures = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Reports" };
builder.Services.AddControllers().AddFeatureGatedControllers(enabledFeatures);
var app = builder.Build();
app.MapControllers();
app.Run();
[ApiController]
[FeatureController("Reports")]
[Route("api/reports")]
public sealed class ReportsController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok(new { Status = "ready" });
}
Feature-Gated Controllers
[FeatureController(...)] accepts one or more names. A marked controller is discoverable when any
name overlaps the supplied enabled set; unmarked controllers remain available. Use a case-insensitive
set consistently with the feature launcher. Register dependencies for every controller retained on
the host. Gating controls discovery; it is not authentication or authorization.
Use the same set with CasCap.Common.Services when background features share those names. If controllers live in separate assemblies, application part selection can gate entire assemblies instead.
Controller Discovery Activity
flowchart TD
DISCOVER["MVC controller discovery"] --> MARKED{"FeatureController attribute?"}
MARKED -->|No| KEEP["Retain controller"]
MARKED -->|Yes| ENABLED{"Any marked feature enabled?"}
ENABLED -->|Yes| KEEP
ENABLED -->|No| REMOVE["Remove controller from discovery"]
KEEP --> ROUTES["Controller routes and API discovery"]
Serilog
SerilogExtensions.GetBootstrapLogger() provides early startup logging. Call
builder.InitializeSerilog() to configure the host pipeline, then initialize OpenTelemetry if
needed. This ordering matters: Serilog initialization clears existing logging providers.
Serilog reads the Serilog section and forwards events to Microsoft logging providers, including
the OpenTelemetry exporter.
The API also accepts an optional configureLogger callback, applied after the standard
defaults and configuration binding. A deliberately reloadable application can use it to attach a
per-host LoggingLevelSwitch to MinimumLevel.ControlledBy. This controls the actual pipeline,
including forwarding, rather than only console output. The application owns validation, monitor
subscription/disposal and its immutable startup baseline; existing calls retain their behavior.
| Extension | Description |
|---|---|
SerilogExtensions.GetBootstrapLogger() |
Creates a bootstrap console logger and wires ApplicationLogging.LoggerFactory |
SerilogWebApplicationBuilderExtensions.InitializeSerilog(builder, categoryName) |
Configures Serilog as the host pipeline and forwards events to registered logging providers |
LoggerConfiguration.AddCasCapDefaults(IConfiguration) |
Applies standard enrichers, console output, health-check filtering, RequestPath removal and configuration binding |
SerilogWebApplicationExtensions.UseCasCapRequestLogging(app, slowRequestThreshold) |
Emits one privacy-safe summary event per HTTP request |
SerilogExtensions.ConsoleLevelSwitch controls console verbosity independently from other sinks. It defaults to Verbose; interactive applications can temporarily raise it to Warning to prevent rendered output from interleaving with logs.
Level Layers
Three independent settings decide whether an event is written:
- The pipeline minimum,
Serilog:MinimumLevel:Default, or aLoggingLevelSwitchattached throughconfigureLogger. - Category overrides. The defaults set
Microsoft.AspNetCoreandSystem.Net.Http.HttpClienttoWarningandMicrosoft.Extensions.HttptoInformation;Serilog:MinimumLevel:Overrideentries replace them. An override applies whatever the pipeline minimum is, so lowering the minimum toDebugdoes not reveal framework categories. - Sink thresholds, such as
ConsoleLevelSwitch, which can only drop events further.
The defaults also exclude events below Warning whose SourceContext starts with
Microsoft.Extensions.Diagnostics.HealthChecks, so the framework's routine health-check
processing stays out of a Debug log while failed checks remain visible. The filter reads only
SourceContext; application events that merely mention health checks are kept.
SerilogExtensions.IsHealthCheckNoise exposes the predicate for custom pipelines.
ASP.NET Core's hosting scope attaches the raw request path to every event logged during a
request. Raw paths can carry record or user identifiers, so the defaults remove RequestPath;
RequestId, TraceId and SpanId still correlate events with their request summary.
Request Summary
app.UseCasCapRequestLogging() logs one event per request with the method, the matched route
template, the status code and the elapsed time:
HTTP GET /api/widgets/{id} responded 200 in 4.2 ms
It never logs the raw path, query string, headers or bodies. A request that matches no endpoint
logs (unmatched) as its route.
| Outcome | Level |
|---|---|
| Unhandled exception or 5xx response | Error |
Failed /healthz probe; non-streaming request slower than the threshold (default five seconds) |
Warning |
| Other 1xx-4xx responses | Information |
| Client cancellation; 404 with no matching endpoint | Debug |
Successful /healthz probe; successful static file |
Verbose |
Register it first, before UseExceptionHandler, so it times the whole pipeline, records
authentication and authorization rejections and leaves the exception itself to the exception
handler, which logs it once:
var app = builder.Build();
app.UseCasCapRequestLogging();
app.UseExceptionHandler();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
OpenTelemetry
InitializeOpenTelemetry registers metrics, traces and logs with OTLP gRPC export. It takes an
IMetricsConfig,
ApplicationMetadata, and optional Redis connection, exporter authentication
and metric/trace customization callbacks.
| Extension | Description |
|---|---|
OpenTelemetryExtensions.InitializeOpenTelemetry(...) |
Registers OpenTelemetry metrics, traces, and logs with OTLP gRPC export |
MeterProviderBuilderExtensions.AddHistogramView(...) |
Registers explicit histogram bucket boundaries for a prefixed instrument |
MetricBoundaries.Symmetric(...) |
Mirrors positive boundaries into a signed set around zero |
Registration is skipped when OtlpExporterEndpoint is null. Development hosts register a Prometheus
exporter; exposing its endpoint still requires application setup. Non-development hosts add
ASP.NET Core, runtime and process metrics. HTTP client tracing is enabled in both environments;
ASP.NET Core and optional Redis tracing are added outside Development.
Configuration Examples
The library consumes IMetricsConfig; it does not bind a fixed AppConfig section. The application
chooses an options type and section. This example uses Telemetry:
using System;
using CasCap.Common.Abstractions;
using CasCap.Common.Extensions;
using CasCap.Common.Models;
using Microsoft.Extensions.Configuration;
using Serilog;
builder.InitializeSerilog();
var telemetry = builder.Configuration.GetSection("Telemetry").Get<TelemetryOptions>()
?? new TelemetryOptions();
builder.InitializeOpenTelemetry(telemetry, new ApplicationMetadata());
public sealed record TelemetryOptions : IMetricsConfig
{
public string MetricNamePrefix { get; init; } = "example";
public string OtelServiceName { get; init; } = "Example.App";
public Uri? OtlpExporterEndpoint { get; init; }
}
Run these registrations before builder.Build() in the Usage example. Place the options type
after the program's top-level statements.
No Telemetry Export
{
"Telemetry": {
"MetricNamePrefix": "example",
"OtelServiceName": "Example.App"
}
}
OTLP Export
{
"Telemetry": {
"MetricNamePrefix": "example",
"OtelServiceName": "Example.App",
"OtlpExporterEndpoint": "http://otel-collector.example.com:4317"
}
}
Use a caller-controlled endpoint and protect exporter credentials with a secret provider. Telemetry can leave the application through the configured collector; review resource attributes and emitted events before enabling it.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. net11.0 is compatible. |
-
net10.0
- CasCap.Common.Abstractions (>= 5.2.0)
- CasCap.Common.Logging (>= 5.2.0)
- CasCap.Common.Net (>= 5.2.0)
- CasCap.Common.Services (>= 5.2.0)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.20.1)
- OpenTelemetry.Exporter.Prometheus.AspNetCore (>= 1.20.1-beta.1)
- OpenTelemetry.Extensions.Hosting (>= 1.20.1)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.20.2)
- OpenTelemetry.Instrumentation.Http (>= 1.20.2)
- OpenTelemetry.Instrumentation.Process (>= 1.20.1-rc.1)
- OpenTelemetry.Instrumentation.Runtime (>= 1.20.1)
- OpenTelemetry.Instrumentation.StackExchangeRedis (>= 1.20.1-beta.1)
- Serilog (>= 4.4.0)
- Serilog.AspNetCore (>= 10.0.0)
- Serilog.Enrichers.AssemblyName (>= 2.0.0)
- Serilog.Enrichers.Environment (>= 3.0.1)
- Serilog.Enrichers.Process (>= 3.0.0)
- Serilog.Enrichers.Span (>= 3.1.0)
- Serilog.Enrichers.Thread (>= 4.0.0)
- Serilog.Exceptions (>= 8.4.0)
- Serilog.Extensions.Hosting (>= 10.0.0)
- Serilog.Extensions.Logging (>= 10.0.0)
- Serilog.Settings.Configuration (>= 10.0.1)
- Serilog.Sinks.Console (>= 6.1.1)
- StackExchange.Redis (>= 3.4.31)
-
net11.0
- CasCap.Common.Abstractions (>= 5.2.0)
- CasCap.Common.Logging (>= 5.2.0)
- CasCap.Common.Net (>= 5.2.0)
- CasCap.Common.Services (>= 5.2.0)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.20.1)
- OpenTelemetry.Exporter.Prometheus.AspNetCore (>= 1.20.1-beta.1)
- OpenTelemetry.Extensions.Hosting (>= 1.20.1)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.20.2)
- OpenTelemetry.Instrumentation.Http (>= 1.20.2)
- OpenTelemetry.Instrumentation.Process (>= 1.20.1-rc.1)
- OpenTelemetry.Instrumentation.Runtime (>= 1.20.1)
- OpenTelemetry.Instrumentation.StackExchangeRedis (>= 1.20.1-beta.1)
- Serilog (>= 4.4.0)
- Serilog.AspNetCore (>= 10.0.0)
- Serilog.Enrichers.AssemblyName (>= 2.0.0)
- Serilog.Enrichers.Environment (>= 3.0.1)
- Serilog.Enrichers.Process (>= 3.0.0)
- Serilog.Enrichers.Span (>= 3.1.0)
- Serilog.Enrichers.Thread (>= 4.0.0)
- Serilog.Exceptions (>= 8.4.0)
- Serilog.Extensions.Hosting (>= 10.0.0)
- Serilog.Extensions.Logging (>= 10.0.0)
- Serilog.Settings.Configuration (>= 10.0.1)
- Serilog.Sinks.Console (>= 6.1.1)
- StackExchange.Redis (>= 3.4.31)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.