Skip to main content

Generated Application Contracts

Overview​

Inlet generates the repetitive application boundary around your domain types. You write commands, business rules, events, and reducers; generated code connects those decisions to HTTP endpoints and client features.

This reference maps the contracts in the Spring sample across its runtime, gateway, and Blazor client. Use it when choosing where to register a capability or tracing a generated type back to its source.

Applies to​

  • The Inlet runtime, gateway, and client generators and their shared attributes.
  • Applications with generator references configured, such as Spring.
  • The SDK packages for each host role; see the package and capability map for their library dependencies and the sample's explicit analyzer references.

Domain Inputs And Generated Outputs​

Domain inputGenerated application surfaceConsumer responsibility
Aggregate state with [GenerateAggregateEndpoints] and commands with [GenerateCommand]Aggregate controller, command DTOs and mappings, client actions/effects/state/reducers, registration methodsImplement the command handlers and event reducers; register the infrastructure and generated features
Projection with [GenerateProjectionEndpoints] and [ProjectionPath]Projection controller, DTOs and mappings, and client projection reducersDefine the read model and its reducers; connect its brook and projection path to the hosts
Saga with [GenerateSagaEndpoints] or its generic input formSaga endpoints, client feature, and runtime registrationDefine saga input, steps, state transitions, and compensation behavior

Generation runs during compilation. Edit the domain input and application configuration, then rebuild the consuming projects to update their generated contracts. Keep business decisions in the handlers and reducers that you own.

That division gives teams one place to review a rule such as “withdraw only an available balance.” It also gives an AI coding assistant a bounded task: change the domain rule, supply its examples and tests, rebuild the contracts, and verify the consumer behavior.

Host Registration Map​

These are different registration surfaces, each with a specific receiver.

HostGenerated method for Spring's domainReceiverIncludes
RuntimeAddMississippiSamplesSpringDomainSilo()IServiceCollectionGenerated aggregate, saga, and projection registrations discovered for the domain
GatewayAddMississippiSamplesSpringDomainServer()IServiceCollectionGenerated aggregate and projection mapper registrations
ClientAddMississippiSamplesSpringDomainClient()MississippiClientBuilderGenerated aggregate and saga Reservoir features, plus projection feature registration

The domain name comes from the domain root namespace. The domain-level generated extension namespaces follow the consuming project's root namespace:

HostSpring extension namespace
RuntimeMississippiSamples.Spring.Runtime.Registrations
GatewayMississippiSamples.Spring.Gateway.Controllers.Mappers
ClientMississippiSamples.Spring.Client.Features

You can compose individual generated registrations instead. Spring's runtime and gateway currently select individual methods, while its client calls the domain-level method. For example, AddBankAccountAggregate() registers runtime behavior, AddBankAccountAggregateMappers() registers gateway mappings, and AddBankAccountAggregateFeature() registers client command handling on IReservoirBuilder.

Individual gateway mapper extensions live in the consuming project's .Controllers.Aggregates.Commands.<Aggregate>.Mappers and .Controllers.Projections.Mappers namespaces. For example, Spring's bank account mapper extensions live in MississippiSamples.Spring.Gateway.Controllers.Aggregates.Commands.BankAccount.Mappers. The combined domain Server extension above lives in .Controllers.Mappers.

Gateway command DTOs live in <Gateway>.Controllers.Aggregates.Commands.<Aggregate>, and their mappers live in that namespace's .Mappers child. The fixed Commands segment keeps these namespaces separate from generated controller types. The aggregate segment retains the domain aggregate namespace path, so commands with the same name in different aggregates have distinct C# contracts. Generated controllers keep their <Gateway>.Controllers.Aggregates namespace.

When upgrading from the shared .Controllers.Aggregates DTO namespace or .Controllers.Aggregates.Mappers mapper namespace, update direct using directives and fully qualified DTO and mapper references to include the Commands and aggregate segments. Generated type names, HTTP routes and JSON payloads stay the same.

Infrastructure Around Generated Registrations​

Generated domain registrations compose application types. Supply their host infrastructure as part of startup:

HostSpring composition to follow
RuntimeOrleans silo and stream provider, event sourcing and snapshot storage, AddInletSilo(), projection assembly scan, and generated domain registrations
GatewayOrleans client, JSON serialization, aggregate and UX projection support, SignalR and Aqueduct services, configured authentication/authorization and AddInletServer(...), projection assembly scan and generated mappers; map controllers and MapInletHub()
ClientAn HttpClient with the gateway base address, AddMississippiClient(...), generated domain features, AddInletClient() and AddInletBlazorSignalR(...) on the Reservoir builder

Use the complete Spring host configuration as a starting point. In particular, retain Spring's explicit AddAqueduct<InletHub>(...) services and matching stream-provider configuration alongside AddInletServer().

Pass all domain projection assemblies together to ScanProjectionAssemblies(...) in each server host. Each call installs registries built from that call's exported projection types; a single combined scan retains mappings for every supplied domain.

Authorization For An Exposed Gateway​

Before exposing a gateway, configure its ASP.NET Core authentication handler, authorization policies, and authentication/authorization middleware. Choose a policy that permits the users, roles, or claims appropriate for the generated application surface.

For example, after defining an application-access policy, replace the bare Inlet registration with this startup configuration:

builder.Services.AddInletServer(options =>
{
options.GeneratedApiAuthorization.Mode =
GeneratedApiAuthorizationMode.RequireAuthorizationForAllGeneratedEndpoints;
options.GeneratedApiAuthorization.DefaultPolicy = "application-access";
options.GeneratedApiAuthorization.AllowAnonymousOptOut = false;
});

GeneratedApiAuthorizationMode is in Mississippi.Inlet.Gateway, with default Disabled. Put [GenerateAuthorization(Policy = "application-access")] metadata on each protected generated command, projection, and saga, or use aggregate-level metadata that covers its controller, and verify every action. Force mode adds a default controller filter only when neither the controller nor any action has explicit authorization metadata. A mixed controller therefore needs explicit protection for its otherwise-unannotated actions. The configuration above complements that deliberate contract coverage.

Protect an exposed MCP endpoint and its tools separately through the application, or restrict them to a trusted local development environment. Generated controller and Inlet subscription authorization settings apply to those interfaces; MCP tools invoke domain grains directly.

The hub applies projection authorization when a client subscribes. Its authorization callback receives the user and a null resource. Use these policies for identity-based access; entity-specific permissions require an application boundary that receives and checks the requested entity ID before granting access.

Verify anonymous and insufficiently privileged requests as well as successful access. Spring auth-proof mode provides executable HTTP 401/403 checks with development identities. Add application-specific SignalR integration tests for allowed and denied subscriptions. Configure the deployment's real authentication mechanism for an exposed application.

Projection Identity Across The Boundary​

Spring's BankAccountBalanceProjection declares these distinct identities:

MetadataValuePurpose
[BrookName]SPRING, BANKING, ACCOUNTSelect the account event stream family
[SnapshotStorageName]SPRING, BANKING, ACCOUNTBALANCESelect the projection's snapshot storage identity
[ProjectionPath]bank-account-balanceConnect the HTTP projection route, client DTO, and subscription path

The entity ID selects the particular account within that family. Generated DTOs retain the projection-path metadata so ScanProjectionDtos(...) can map a DTO type to its server route.

With the default automatic fetcher route prefix, the client reads:

RequestRoute
Latest projection/api/projections/bank-account-balance/{entityId}
Projection at a notified version/api/projections/bank-account-balance/{entityId}/at/{version}

The fetcher escapes the entity ID as a URL path segment. Latest reads obtain the version from the HTTP ETag. Configure WithRoutePrefix(...) when your projection endpoints use a different prefix, and keep the server routes aligned with it.

Command State And Projection State​

A generated command action starts an HTTP operation through a generated effect. For Spring's DepositFundsAction, the generated lifecycle actions are DepositFundsExecutingAction, DepositFundsSucceededAction, and DepositFundsFailedAction.

Use command state to show progress and the command's result. Use projection state to display the read model. A successful command response and a refreshed projection are separate observations; keep the loading and error presentation for each tied to its own state.

One possible successful projection update sequence is shown below. The arrows illustrate the data path rather than an enforced ordering between concurrent HTTP reads:

Initial, refresh, and notification-triggered reads can complete out of order. The projection reducers assign the returned data and version as responses arrive. If a view requires monotonic versions, supply application coordination that serializes its reads or rejects older results before they update state.

The notification identifies what to read. The HTTP request supplies the projection data, and Reservoir publishes the resulting state to subscribed components. On a successful transport reconnection, Inlet re-establishes its active subscriptions and fetches their latest projections.

Source Code​

Summary​

Domain metadata aligns generated contracts across hosts. Register each host's infrastructure, add its generated domain surface, and use command and projection state for their respective user-visible outcomes.

Next Steps​