# .NET Architecture

## Intent

Architecture in a .NET backend is five projects with explicit composition roots. The shared provisions live on the stack-neutral page ([Backend architecture](https://litespec.dev/2.0.0/backend/architecture.md)); this page holds what dotnet alone requires.

## Standards

### Use five application projects

**Requirement:** An application MUST use Domain, Application.Abstractions, Application, Infrastructure, and WebApi as its five baseline projects.

**Rationale:** `Application.Abstractions` holds the contracts that more than one module names: the pipeline's own positions, the cross-module ports, the transport-neutral failures, and the published integration events. It references Domain and the required LiteBus module abstractions, and nothing else. No type in it can name a use case, a handler, or a module.

That refusal is the reason it is a project rather than a folder. A folder inside Application cannot decline what a developer puts in it, and the folder that tries becomes the place every unplaced type goes.

An implementation never belongs there. The project name states the test, and a type that cannot pass it belongs to a module under `litespec/backend/architecture#place-a-type-at-the-lowest-folder-that-holds-its-consumers`.

`AppHost` and `ServiceDefaults` support local hosting and diagnostics. They are hosts, not application layers.

This realizes litespec/backend/architecture#use-five-application-parts in the dotnet stack.

**Example:**

```text
apps/api/src/{ProjectName}.Domain/
apps/api/src/{ProjectName}.Application.Abstractions/
apps/api/src/{ProjectName}.Application/
apps/api/src/{ProjectName}.Infrastructure/
apps/api/src/{ProjectName}.WebApi/
```

### Keep one Application assembly

**Requirement:** An application MUST place commands, queries, results, validators, handlers, reactions, and module-owned ports in one Application project, and cross-module contracts in Application.Abstractions.

**Rationale:** Separate Write, Read, Contracts, and event-handler assemblies are outside this stack. The separation this stack keeps is the one [Fowler describes as CQRS](https://www.martinfowler.com/bliki/CQRS.html), which separates the command and query models rather than the assemblies holding them. Splitting assemblies buys a deployment boundary the stack does not use, and costs a project reference that every use case has to cross.

This realizes litespec/backend/architecture#keep-one-application-part in the dotnet stack.

### Keep implementation types internal

**Requirement:** A handler, validator, definition, persistence implementation, or endpoint implementation MUST be declared `internal sealed`.

**Rationale:** Messages, results, assembly markers, and ports stay public only when another project uses them. Assembly scanning is not a reason to widen visibility.

This realizes litespec/backend/architecture#keep-implementation-types-hidden in the dotnet stack.

## Conventions

### Keep composition in hosts

**Default:** Keep service registration in `Program.cs` and host registration modules.

**Replacement:** A consumer replaces this default by recording an Exception for this provision, with reason and review date.

**Rationale:** Domain and Application declare abstractions, so a registration call inside either inverts the dependency direction.

This realizes litespec/backend/architecture#keep-service-registration-in-hosts in the dotnet stack.

**Example:** One registration entry point per outer layer has this shape:

```text
InfrastructureServiceRegistration.AddInfrastructure(...)
WebApiServiceRegistration.AddWebApi(...)
```

`AddInfrastructure` receives configuration and host environment values needed to bind and validate provider options. `AddWebApi` owns Problem Details, authentication, authorization, endpoint discovery, and OpenAPI. `Program.cs` keeps their call order visible.

### Use one public assembly marker per scanned project

**Default:** Expose one `public static` assembly marker in each project that an approved scanner reads.

**Replacement:** A consumer replaces this default by recording an Exception for this provision, with reason and review date.

**Rationale:** The marker gives the scanner an assembly reference while the scanned handlers stay internal.

## Verification

| ID | Mark | Evidence |
|:---|:---|:---|
| litespec/backend/dotnet/architecture#use-five-application-projects | guidance | Does the solution hold exactly the five baseline projects? |
| litespec/backend/dotnet/architecture#keep-one-application-assembly | guidance | Does one Application project hold every message, handler, and module-owned port? |
| litespec/backend/dotnet/architecture#keep-implementation-types-internal | guidance | Is every handler, validator, definition, and endpoint implementation `internal` and `sealed`? |
| litespec/backend/dotnet/architecture#keep-composition-in-hosts | guidance | Does all service registration live in hosts and host modules? |
| litespec/backend/dotnet/architecture#use-one-public-assembly-marker-per-scanned-project | guidance | Does each scanned project expose exactly one public assembly marker? |
