Table of Contents

ASP.NET Core Endpoint Governance

AsiBackbone.AspNetCore includes an optional ergonomic endpoint-governance layer for the common ASP.NET Core case where a host wants to protect a Minimal API endpoint or controller action with AsiBackbone metadata.

This layer is intentionally a host adapter. It does not replace Core primitives, make persistence durable, create transactions, or certify audit immutability. It reduces endpoint boilerplate while keeping storage, transaction boundaries, capability-grant validation, and outbox behavior under host ownership.

Register services and middleware

builder.Services.AddAsiBackboneAspNetCore();

WebApplication app = builder.Build();

app.UseAsiBackboneEndpointGovernance();

Place UseAsiBackboneEndpointGovernance() after routing has selected an endpoint and before the protected endpoint executes. In a typical minimal host this means before MapControllers() and before mapped endpoints are executed by endpoint routing.

Hosts that use policy metadata should register an IAsiBackbonePolicyEvaluator<AsiBackboneConstraintEvaluationContext>. Hosts that use capability metadata should register an IAsiBackboneEndpointCapabilityGrantValidator. Hosts that request audit emission should register a host-owned IAsiBackboneAuditSink.

Minimal API / fluent endpoint path

app.MapPost("/high-risk-action", handler)
    .RequireGovernancePolicy<MyStrictPolicy>()
    .RequireLiabilityHandshake()
    .RequireCapabilityGrant("robotics.execute")
    .EmitGovernanceAudit();

The fluent methods add endpoint metadata. The middleware resolves that metadata into an AsiBackboneEndpointGovernanceDescriptor, builds a framework-neutral evaluation context, and delegates policy evaluation, capability validation, handshake creation, and audit emission to registered host-owned services.

Endpoints that intentionally prefer a latency-optimized first-block fast-abort policy path can add endpoint metadata:

app.MapPost("/high-risk-action", handler)
    .RequireGovernancePolicy<MyStrictPolicy>()
    .ShortCircuitOnFirstDenial();

The descriptor exposes this as ShortCircuitOnFirstDenial and includes endpoint.short_circuit_on_first_denial in descriptor metadata. Host-owned policy wiring remains responsible for mapping that endpoint preference into AsiBackbonePolicyEvaluatorOptions.ShortCircuitOnFirstDenial when constructing or resolving the evaluator.

Controller/action attribute path

[RequireGovernancePolicy(typeof(MyStrictPolicy))]
[RequireLiabilityHandshake]
[RequireCapabilityGrant("robotics.execute")]
[EmitGovernanceAudit]
public IActionResult ExecuteHighRiskAction()
{
    return Ok();
}

The attribute model is designed to feel familiar to ASP.NET Core developers who already use attributes such as [Authorize]. The attributes only add metadata. They do not by themselves validate capability grants, write durable audit records, or provide transaction guarantees.

Endpoint-scoped fast-abort metadata is also available as an attribute:

[RequireGovernancePolicy(typeof(MyStrictPolicy))]
[ShortCircuitOnFirstDenial]
public IActionResult ExecuteLatencySensitiveAction()
{
    return Ok();
}

What the ergonomic layer does

When endpoint governance metadata is present, the middleware can:

  1. Resolve the selected endpoint metadata.
  2. Build a safe AsiBackboneConstraintEvaluationContext using HTTP request correlation data.
  3. Invoke the host-registered policy evaluator when policy metadata exists.
  4. Invoke the host-registered capability validator when capability scopes exist.
  5. Emit AuditResidue through the host-owned audit sink when audit emission is requested.
  6. Return an acknowledgment challenge when the governance decision requires acknowledgment and the endpoint requested liability-handshake support.
  7. Block execution with a safe HTTP result when policy, capability, or configuration checks fail closed.

Host-owned boundaries

The ergonomic endpoint layer deliberately does not own persistence. Durable audit storage, outbox persistence, transactional consistency, signing, key management, and replay protection remain host responsibilities.

Concern Owner
Endpoint metadata and middleware orchestration AsiBackbone.AspNetCore
Policy constraints and decision policy Host/Core evaluator registration
Capability-grant source, proof validation, and replay handling Host-owned IAsiBackboneEndpointCapabilityGrantValidator
Audit sink, ledger store, outbox store, and transactions Host-owned storage/integration layer
Legal/compliance interpretation Host governance process

Failure behavior

AsiBackboneEndpointGovernanceOptions controls fail-closed behavior for missing host services:

builder.Services.Configure<AsiBackboneEndpointGovernanceOptions>(options =>
{
    options.FailClosedWhenPolicyEvaluatorMissing = true;
    options.FailClosedWhenCapabilityValidatorMissing = true;
    options.FailClosedWhenAuditSinkMissing = true;
});

Failing closed is the default because an endpoint that declares governance intent should not silently bypass missing policy, capability, or audit services. Advanced hosts can relax this behavior during migration, but should document why.

When middleware blocks execution and no explicit FailureResult is supplied, the default response is a bodyless 403 Forbidden status result. This low-allocation default is intentional for high-volume rejection traffic such as probing, credential stuffing, or denial flooding, and it avoids exposing governance reason codes or policy details in generic denial responses.

The default endpoint governance service uses this generic 403 path for ordinary denied governance decisions when DeniedStatusCode remains 403. Configuration failures and capability-validator setup failures still return explicit ProblemDetails responses because they indicate host setup issues rather than routine request denial. Non-403 governance outcomes continue to use the HTTP result mapping options.

Custom failure results remain supported. A host-owned governance service can return an explicit FailureResult, and that result is executed instead of the generic default. Hosts that prefer richer API responses for generic 403 denials can configure a safe factory:

builder.Services.Configure<AsiBackboneEndpointGovernanceOptions>(options =>
{
    options.DefaultForbiddenResultFactory = _ => Results.Problem(
        title: "Forbidden.",
        detail: "The request is not allowed.",
        statusCode: StatusCodes.Status403Forbidden);
});

Use richer ProblemDetails responses only when the response body is safe for the deployment. Do not include sensitive policy internals, capability-token details, audit identifiers, or reason messages unless the host has explicitly decided those values are safe to expose.

Development diagnostics

Local development hosts can opt into richer ProblemDetails diagnostics for endpoint governance failures:

builder.Services.Configure<AsiBackboneEndpointGovernanceOptions>(options =>
{
    options.EnableDevelopmentDiagnostics = builder.Environment.IsDevelopment();
    options.DevelopmentDiagnosticsDocumentationBaseUrl = "https://cdcavell.github.io/AsiBackbone/articles/";
});

Diagnostics are emitted only when enabled and when the request service provider exposes an IWebHostEnvironment whose environment name is Development. Production-safe defaults remain conservative: diagnostics are off by default and ordinary denied decisions keep the bodyless generic 403 path unless diagnostics are explicitly enabled in development.

Development diagnostics may include the governance outcome, reason codes and messages, endpoint operation name, policy marker types, requested capability scopes, decision stage, correlation/trace identifiers, redacted metadata, and a troubleshooting documentation link.

See Endpoint Governance Development Diagnostics for response examples, common failures, and redaction rules.

Strict metadata enforcement

By default, endpoint governance remains opt-in. Endpoints without AsiBackbone governance metadata pass through to the next middleware. This mirrors common ASP.NET Core adoption patterns and preserves backwards compatibility.

Regulated or governance-sensitive hosts can enable fail-closed metadata enforcement:

builder.Services.Configure<AsiBackboneEndpointGovernanceOptions>(options =>
{
    options.RequireGovernanceMetadata = true;
});

When enabled, selected endpoints without governance metadata are blocked before execution unless the endpoint explicitly allows missing governance metadata. This option does not replace ASP.NET Core authentication or authorization. It only prevents accidental governance bypass caused by missing AsiBackbone endpoint metadata. The default strict-metadata rejection also uses the bodyless generic 403 Forbidden response unless DefaultForbiddenResultFactory is configured or development diagnostics are enabled in a Development environment.

Relation to full manual wire-up

Manual wire-up remains the most explicit path for complex flows. Use manual integration when the endpoint requires a custom transaction boundary, multiple persistence stores, custom signing, outbox enqueue-before-execution semantics, or workflow-specific acknowledgment handling.

Use the ergonomic layer when the endpoint follows the common pattern: read metadata, evaluate policy, validate capability, optionally emit audit residue, and either continue or return a safe governance response.