Cohesive.Adapters.AspNet 0.1.0-alpha.120

This is a prerelease version of Cohesive.Adapters.AspNet.
dotnet add package Cohesive.Adapters.AspNet --version 0.1.0-alpha.120
                    
NuGet\Install-Package Cohesive.Adapters.AspNet -Version 0.1.0-alpha.120
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cohesive.Adapters.AspNet" Version="0.1.0-alpha.120" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cohesive.Adapters.AspNet" Version="0.1.0-alpha.120" />
                    
Directory.Packages.props
<PackageReference Include="Cohesive.Adapters.AspNet" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cohesive.Adapters.AspNet --version 0.1.0-alpha.120
                    
#r "nuget: Cohesive.Adapters.AspNet, 0.1.0-alpha.120"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cohesive.Adapters.AspNet@0.1.0-alpha.120
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cohesive.Adapters.AspNet&version=0.1.0-alpha.120&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Cohesive.Adapters.AspNet&version=0.1.0-alpha.120&prerelease
                    
Install as a Cake Tool

Cohesive.Adapters.AspNet

ASP.NET Core endpoint and request-binding adapters for Cohesive APIs, entities, relations, processes, and identity context.

Install

dotnet add package Cohesive.Adapters.AspNet

Use When

  • You want to expose Cohesive API declarations through ASP.NET Core endpoints.
  • You need route builders for entity operations, relation queries, process execution, or process status.
  • You want ASP.NET request identity and scope policy enforcement to flow into Cohesive operation context.

Example

using Cohesive.Adapters.AspNet.Entities;
using Cohesive.Api;
using Microsoft.AspNetCore.Http;

var api = Api.Define("Notes");
var getNote = api.Entity<NoteResource>()
    .Query("Get")
    .Route("GET", "/notes/{id}")
    .RouteParameter<string>("id")
    .Returns<NoteResource>()
    .Build();

app.MapEntityApiDefinition(api.Build(), new EntityApiEndpointOptions
{
    Entity = NoteEntity.Instance.Definition
}
    .Bind(getNote.Get(static (_, snapshot) =>
        Results.Ok(ToResource(snapshot)))));

Generic semantic API projection

The root Cohesive.Adapters.AspNet namespace owns the direct Minimal API interpretation of ApiDefinition and ApiEndpoint. Mapping preserves each original ApiOperation, HttpBinding, authorization requirement, scope policy, and semantic reference as endpoint metadata. Definitions are mapped in stable declaration order, and the optional callback can attach additional ASP.NET metadata without changing semantic authority.

using Cohesive.Adapters.AspNet;
using Cohesive.Api;

var definition = Api.Define("Shipping")
    .Query("Health")
        .Route("GET", "/health")
        .Returns<HealthResponse>()
        .Done()
    .Build();

app.MapApiDefinition(
    definition,
    operation => operation.Name switch
    {
        "Health" => () => Results.Ok(new HealthResponse("ready")),
        _ => throw new InvalidOperationException($"No handler is bound for '{operation.Id}'.")
    });

For secured operations, supply an AspNetAuthorizationPolicyResolver. Mapping fails closed before registering any route when a definition contains an authorization requirement without a valid ASP.NET policy projection.

This surface previously lived in the Cohesive.Api assembly and namespace. Existing ASP.NET hosts must reference this adapter and add using Cohesive.Adapters.AspNet;; no compatibility shim remains in the host-neutral package.

Canonical relation/query evaluation

Relation/query endpoints author a new RelationQueryEvaluation for each HTTP request and delegate the complete compile-realize-plan-execute pipeline to IRelationQueryEvaluator. The request context supplies the evaluation identity so runtime evidence, diagnostics, and traces remain correlated with the HTTP request. The result mapper is required: the in-process evaluation outcome deliberately is not treated as a default wire contract.

using Cohesive.Adapters.AspNet.Relations;
using Cohesive.Model;
using Cohesive.Relations.Authoring;
using Cohesive.Relations.Execution;

// Configure an evaluator with the application's placement policy and source readers.
builder.Services.AddSingleton<IRelationQueryEvaluator>(relationQueryEvaluator);

var api = Api.Define("Transportation");
var loads = api.Action("SearchLoads")
    .Route("GET", "/loads")
    .Query<SearchLoadsRequest>()
    .Returns<SearchLoadsResponse>()
    .Build();

app.MapRelationQueryApiDefinition(api.Build(), new RelationQueryApiEndpointOptions()
    .Bind(loads.RelationQuery(
        (context, request) =>
        {
            var search = (SearchLoadsRequest)request!;
            return loadsByCustomerDocument
                .Evaluate(context.EvaluationId, loadShapeDocuments, relationshipCatalog)
                .Set(customerNameParameterId, ObservationValue.FromString(search.CustomerName))
                .Select(loadRowsId)
                .Build();
        },
        (_, outcome) =>
        {
            if (outcome.Result is not { IsSuccessful: true } result)
                return Results.UnprocessableEntity(outcome.Compilation.Diagnostics);

            var rows = result.QueryResults.Single(branch => branch.Result == loadRowsId).Rows;
            return Results.Ok(new SearchLoadsResponse(rows));
        })));

EvaluationIdSelector can override the default aspnet/request/.../operation/... convention when an application already has a stable correlation identity. The endpoint verifies that the per-request factory and evaluator preserve the selected identity and passes one effective token, linking operation cancellation with HttpContext.RequestAborted, through request binding, evaluation authoring, execution, and result mapping.

Entity-declared query endpoints use this same canonical binding rather than a repository-specific Entity query path. Map point reads and writes with the Entity adapter, then map the query endpoint from the same API definition with the Relations adapter. Each mapper emits only its bound endpoints, so the route is created exactly once:

var definition = api.Build();

app.MapEntityApiDefinition(definition, new EntityApiEndpointOptions
{
    Entity = NoteEntity.Instance.Definition
}.Bind(noteGet.Get(static (_, snapshot) => Results.Ok(ToResource(snapshot)))));

app.MapRelationQueryApiDefinition(definition, new RelationQueryApiEndpointOptions()
    .Bind(noteSearch.RelationQuery(
        (context, request) => NoteQueries.Search(
            context.EvaluationId,
            (SearchNotesRequest)request!),
        static (_, outcome) => MapSearchResponse(outcome))));

The required result mapper receives the complete canonical outcome, including rows, aggregations, requirement gaps, diagnostics, and provenance, and remains responsible for the endpoint's HTTP status policy.

Canonical Process observation reads

MapProcessExecutionInspectApi, MapProcessExecutionExplainApi, and MapProcessExecutionTracesApi project the existing route-neutral ExecutionControlApiCatalog handles as HTTP GETs without adding status, explanation, or trace DTOs. Each route carries only the logical Process identity. Their shared ProcessExecutionAuthorityScopeResolver must derive authority and tenant from authenticated server-side identity and scope evidence; it must not copy them from caller data. The required authorization-policy resolver maps each catalog semantic authorization requirement to ASP.NET authorization metadata.

using Cohesive.Adapters.AspNet.Processes;
using Cohesive.Api.Execution;

var executionControl = ExecutionControlApiCatalog.Create();

app.MapProcessExecutionInspectApi(
    executionControl.Inspect,
    "/api/processes/{processInstanceId}",
    (operationContext, httpContext, processInstanceId) =>
        ResolveAuthorizedProcessScope(operationContext, httpContext, processInstanceId),
    (operation, requirement) => ResolveAuthorizationPolicy(requirement));

app.MapProcessExecutionExplainApi(
    executionControl.Explain,
    "/api/processes/{processInstanceId}/explain",
    (operationContext, httpContext, processInstanceId) =>
        ResolveAuthorizedProcessScope(operationContext, httpContext, processInstanceId),
    (operation, requirement) => ResolveAuthorizationPolicy(requirement));

app.MapProcessExecutionTracesApi(
    executionControl.Traces,
    "/api/processes/{processInstanceId}/traces",
    (operationContext, httpContext, processInstanceId) =>
        ResolveAuthorizedProcessScope(operationContext, httpContext, processInstanceId),
    (operation, requirement) => ResolveAuthorizationPolicy(requirement));

The inspect binding resolves IProcessExecutionRepository, performs its provider-neutral logical read, and returns only a retained canonical ExecutionStatus inside the catalog's existing ExecutionControlResult with exact Inspected disposition. Missing executions and pending admissions without canonical status produce the same opaque not-found problem; provider lifecycle values are never promoted into semantic status. The explain binding resolves IProcessExecutionExplainRepository and writes the successful ExecutionExplainArtifact as exact canonical bytes from ExecutionExplainJsonSerializer. Missing or malformed explanation targets use the catalog's opaque problem variants. Conflicting status, runtime, or trace affinity fails closed. The original catalog remains route-neutral and unchanged. The trace binding resolves IProcessExecutionTraceRepository; available artifacts are written as exact canonical bytes from ProcessExecutionTraceJsonSerializer, while missing, active, and terminal-without-artifact states map to the catalog's opaque not-found, conflict, and precondition-failed results.

  • Cohesive.Api for semantic API declarations.
  • Cohesive.Api.Execution for the canonical execution-control catalog and safe result projections.
  • Cohesive.Identity for identity context and scope resolution.
  • Cohesive.Processes, Cohesive.Relations, and Cohesive.Storage for the runtime surfaces exposed by endpoints.

Declared service operations

For an admitted ServiceRuntime, MapServiceTransition<TInput,TOutcome> projects the operation without per-route repository loading or commit callbacks:

using Cohesive.Adapters.AspNet.Services;

app.MapServiceTransition<ReviseNote, bool>(
    runtime, "revise", "/notes/{id}/revise",
    authorizationPolicyResolver: (_, requirement) => requirement.Id);

The CLR types must match the referenced Transition contracts. The caller sends the opaque reviewed token in X-Expected-Concurrency-Token and receives the next token in the same response header. The response body is the Transition outcome. Routes retain standard API metadata and native ASP.NET authorization policy associations, while direct and HTTP calls both pass the runtime's mandatory authority binding. Repository factories are not resolved during mapping. This initial profile supports existing subjects without emissions; see its guarantees and qualification.

Process entries and lifecycle controls project their native command contracts through the same service runtime:

app.MapServiceProcessStart(runtime, "publish", "/notes/publish",
    authorizationPolicyResolver: (_, requirement) => requirement.Id);
app.MapServiceProcessControl<PauseProcessCommand>(runtime, "pause", "/notes/pause",
    authorizationPolicyResolver: (_, requirement) => requirement.Id);

PauseProcessCommand is the native Cohesive.Execution contract. A mismatched command CLR type fails mapping. Native API result definitions determine statuses and response bodies. Service admission failures use the existing ExecutionApiProblem; native Process decisions retain their own result. Start/control authority and exact-target admission run in the shared service runtime, while ASP.NET policy metadata remains an additional host integration.

Declared terminal results use MapServiceProcessResult<TResponse> with the portable service document, a lazy runtime resolver, operation identity, GET route and a pure PortableValue response projection. The exact Process remains the output-contract authority. Declaration-derived metadata preserves result alternatives, capability requirements and supplied scope policies without constructing repositories. Invocation checks that the resolved service has the registered identity, revision and fingerprint, then uses the runtime's protected terminal reader. Success emits the selected response view; pending and rejected reads use the shared declared problem/status projection. No entity concurrency token is emitted.

For example, a compiler may return diagnostics without creating an entity. Its result endpoint can return that retained output directly rather than selecting a nonexistent entity receipt. Tests exercise successful serialization, forbidden reads without protected storage access, pending HTTP 202, lazy construction and rejection of a mismatched runtime. These are mapped endpoint tests, not deployed middleware or remote-provider qualification.

Process start and lifecycle-control endpoints also accept a portable service declaration plus a lazy runtime resolver. ServiceApiProjection.ProjectProcess<TRequest> derives their native command types, result alternatives and service authorization requirements without creating execution bindings. Both eager and lazy overloads use the same request reader and invocation path. The lazy resolver must return the registered service identity, revision and fingerprint; mismatch fails before dispatch. Host scope policies can be attached explicitly. Inspection and Signal ingress are rejected by the same lifecycle admission rule at projection and runtime binding, rather than generating unusable endpoints.

For a domain-specific request body, use ServiceApiProjection.ProjectProcessInput<TRequest> and MapServiceProcessInput<TRequest>. A synchronous medium binder returns native command/idempotency/ continuation identities and an ObservationValue input; it must perform no reads or writes and must preserve all retry values. The service runtime chooses the exact Process and trusted authority, validates input against its Process-owned portable contract, and dispatches native admission. The response retains native admission/conflict outcomes; it does not imply workflow completion. The medium request is a projection, not a competing semantic input contract. This profile does not add bounded completion waiting or custom result-read orchestration to starts.

Declared queries use ServiceApiProjection.ProjectQuery<TRequest,TResponse> and MapServiceQuery<TRequest,TResponse>. Registration validates the service/query operation and attaches host scope policies without resolving runtime/evaluator dependencies. The pure request projection supplies caller parameters; ServiceRuntime injects the trusted scope parameter and rejects attempted scope overrides before evaluator resolution. Evaluation identity reuses the existing relation-query HTTP convention, and the native runtime retains compilation, output-demand and provider semantics.

The pure response projection receives the complete native outcome, including failed evaluations, so it can preserve/redact native phase diagnostics intentionally. A successful outcome uses the primary response; failed evaluation uses the typed queryEvaluationFailed alternative. Admission failures use the separate standard admissionValidationFailed problem. Both validation alternatives are represented in generated API contracts. Provider exceptions and cancellation propagate normally; there is no hidden retry or result cache. The mapper adds no query execution algorithm.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-alpha.120 43 9/29/2026
0.1.0-alpha.119 41 9/29/2026
0.1.0-alpha.118 53 9/29/2026
0.1.0-alpha.117 64 9/27/2026
0.1.0-alpha.116 58 9/26/2026
0.1.0-alpha.115 84 9/26/2026
0.1.0-alpha.114 69 9/24/2026
0.1.0-alpha.113 61 9/24/2026
0.1.0-alpha.112 61 9/23/2026
0.1.0-alpha.111 60 9/23/2026
0.1.0-alpha.110 59 9/23/2026
0.1.0-alpha.109.1 59 9/23/2026
0.1.0-alpha.109 63 9/23/2026
0.1.0-alpha.108 68 9/21/2026
0.1.0-alpha.107 55 9/21/2026
0.1.0-alpha.106 57 9/21/2026
0.1.0-alpha.105 50 9/21/2026
0.1.0-alpha.104 62 9/21/2026
0.1.0-alpha.103 60 9/21/2026
0.1.0-alpha.102 60 9/21/2026
Loading failed