# server aspnet

Source: https://apigenie.pl/techdocs/reference/cli-generate_server_aspnet

Generate an ASP.NET Core server in C#, built on Minimal APIs.

From an AsyncAPI document, the command generates an ASP.NET Core Kafka application instead; see
[apigenie-generator server aspnet (AsyncAPI)](/techdocs/reference/cli-generate_server_aspnet_asyncapi).

## Usage

```sh
apigenie-generator server aspnet [...OPTIONS] INPUT_FILE
```

## Description

The input must be an OpenAPI 3.0, 3.1 or 3.2 document. Convert Swagger 2.0 documents with
[`apigenie convert`](/techdocs/reference/cli-convert), and bundle documents referencing other files
with [`apigenie bundle`](/techdocs/reference/cli-bundle).

The generated project targets .NET 8 (or 9 and 10, see `target_framework`) and uses only the
shared framework, without NuGet packages:

```
PetStore.csproj
Program.cs                  the host, written only when missing
README.md
ApiRegistration.cs          MapPetStoreApi(): maps the endpoints of all operations
Apis/IPetsApi.cs            one interface per group of operations
Apis/PetsApi.cs             its implementation, written only when missing
Endpoints/PetsEndpoints.cs  routes, parameter binding, validation and metadata
Models/Pet.cs               records and enums of the schemas
Infrastructure/*.cs         helpers used by the generated code
```

Operations are grouped by their first tag (or by the first segment of their paths). Each group
gets an interface whose methods return the responses of the operation as a union of typed
results, so the compiler accepts only declared responses:

```csharp
public interface IPetsApi
{
    /// <summary>Find a pet</summary>
    /// <remarks>GET /pets/{petId}</remarks>
    Task<Results<Ok<Pet>, NotFound, GoneResult<Error>>> GetPet(long petId, CancellationToken cancellationToken);
}
```

Implementations return `TypedResults.Ok(pet)`, `TypedResults.NotFound()` and the like. Statuses
without a `TypedResults` method (403, 410, 429, 500, ...) have result types of their own, created
with `ApiResults.Gone(error)`. All results describe their responses in the endpoint metadata, so
OpenAPI documents produced by ASP.NET Core match the input.

The endpoints bind parameters from the path, the query, headers and cookies, with the styles of
the document (exploded or delimited arrays), JSON, text, binary, form and multipart bodies, and
resolve the implementation from the services of the request:

```csharp
var app = builder.Build();
app.MapPetStoreApi();
```

Models are records with `required` properties, System.Text.Json attributes and DataAnnotations
attributes for the constraints of the schemas (`minimum`, `maxLength`, `pattern`, `format: email`,
`maxItems`, ...). An endpoint filter checks them, and the values of enums, before the
implementation is called, and answers invalid requests with 400 validation problem details.

- `oneOf` and `anyOf` with a discriminator become abstract records with `[JsonPolymorphic]`
  attributes, and their variants derive from them. On .NET 8, System.Text.Json reads the
  discriminator only as the first property of an object.
- `allOf` referencing a schema with a discriminator becomes inheritance; other `allOf` schemas are
  merged into one record.
- String enums become C# enums whose converters read and write the values of the document, e.g.
  `in-progress`. Integer enums keep their values. The `x-enum-varnames` extension names members.
- Inline object and enum schemas get types named after their location, e.g. `PetOwner` for the
  `owner` property of `Pet`. Identical inline schemas share a type.
- Schemas whose names would clash with types of .NET (`Task`, `File`, `Environment`, ...) get a
  `Model` suffix.

Operations with security requirements call `RequireAuthorization()`; configure the authentication
schemes in `Program.cs`, which lists the schemes of the document.

Not supported: `oneOf` and `anyOf` without a discriminator whose members have different types
(typed `object`; members of one type, e.g. strings of different formats, give that type), `not`,
`if`/`then`/`else`, separate request and response variants of models with `readOnly` and
`writeOnly` properties (such properties are optional), `prefixItems`, `patternProperties`,
`multipleOf`, `dependentRequired`, `dependentSchemas`, `unevaluatedProperties`, object query
parameters (`deepObject`, left out with a warning), parameters described by `content` (left out
with a warning), the `deepObject` encoding and the constraints of form fields, response headers,
more than one media type per response (JSON wins: no `text/event-stream`, JSON Lines or binary
alternatives), callbacks and webhooks, operation and path servers (every route is below the path
of the first server), and OAuth 2.0 scopes (operations only call `RequireAuthorization()` with the
default policy).

## Extensions

| Extension | Effect |
| --------- | ------ |
| `x-apigenie.codegen.controller-name` | on an operation or its path item: the group (API interface) of the operation, whatever `grouping` says |
| `x-apigenie.codegen.action-name` | name of the method of an operation, when `action_naming` lists `extension` |
| `x-apigenie.codegen.disabled` | `true` on an operation or its path item leaves the operation out, unless `skip_disabled` is `false` |
| `x-internal` | `true` on an operation leaves it out |
| `x-enum-varnames`, `x-enum-names` | names of the members of an enum, in PascalCase |
| `x-enum-descriptions`, `x-enumDescriptions` | documentation comments of the members of an enum |
| `x-defaultMapping` | `defaultMapping` of a discriminator in OpenAPI 3.0 and 3.1 documents: the schema of the values whose discriminator value isn't mapped |

The extensions can live in an overlay for this target instead of in the document, e.g.
`aspnet.overlay.yaml`:

```yaml
overlay: 1.0.0
info:
  title: ASP.NET names
  version: 1.0.0
actions:
  - target: $.components.schemas.PetStatus
    update:
      x-enum-varnames: [Available, OnHold, Sold]
  - target: $.paths['/pets']
    update:
      x-apigenie:
        codegen:
          controller-name: Animals
```

```sh
apigenie-generator server aspnet openapi.yaml --overlay aspnet.overlay.yaml -o out
```

## Options

### -c, --config

Path to the configuration file to use. See the "Configuration" section for more information.

### --overlay OVERLAY

Path to an OpenAPI Overlay (1.0 to 1.2) applied to the input before generating, e.g. one setting the
extensions of the "Extensions" section. Can be repeated: the overlays apply in order, after those
listed under `commands.generate.server_aspnet.overlay` in the configuration file (with paths
relative to it). Warnings and errors about a value an overlay set point to the overlay.

### --strict

Makes an overlay action whose target selects nothing an error (exit status 2, nothing is generated)
instead of a warning (`OVERLAY:LINE:COL: action #N (TARGET) selects no nodes.`).

### -o, --output

Directory where the project is generated.

### --package-name

Root namespace of the generated code, e.g. `Acme.PetStore`; also the name of the project.
Defaults to the title of the API.

### --package-version

Version of the project. Defaults to the version of the API when it's a valid .NET version, or
`1.0.0`.

### -p, --property NAME=VALUE

Sets an option (see below), e.g. `-p layout=sources`; can be repeated. Options given on the
command line take precedence over the configuration file. OpenAPI documents only: using it with an
AsyncAPI document is an error.

## Configuration

The options are read from `commands.generate.server_aspnet`. Its `asyncapi` section configures
the generation from AsyncAPI documents (see
[apigenie-generator server aspnet (AsyncAPI)](/techdocs/reference/cli-generate_server_aspnet_asyncapi#configuration)).

```yaml
version: '1.0'
commands:
  generate:
    server_aspnet:
      namespace: Acme.PetStore
      target_framework: net10.0
      grouping: url
```

| Option | Values | Description |
| ------ | ------ | ----------- |
| `layout` | `project`, `sources` | `project` (default): a complete project (.csproj, Program.cs, README.md); `sources`: only the generated sources, for an existing project |
| `namespace` | namespace | Root namespace of the generated code (also `--package-name`); derived from the API title by default |
| `target_framework` | `net8.0`, `net9.0`, `net10.0` | Target framework of the project (default: `net8.0`) |
| `grouping` | `tag`, `url` | Grouping of operations into API interfaces: by their first tag (default), or by the first segment of their paths |
| `action_naming` | `id`, `extension`, `url` | Sources of method names, in order of preference (default: `id`, `url`) |
| `validation` | `filter`, `none` | `filter` (default): an endpoint filter validates parameters and bodies against their DataAnnotations; `none`: attributes only |
| `authorization` | `require`, `none` | `require` (default): operations with security requirements call `RequireAuthorization()`; `none`: no authorization metadata |
| `base_path` | `servers`, `none` | `servers` (default): routes are prefixed with the path of the first server URL; `none`: no prefix |
| `program` | `true`, `false` | Generate Program.cs and stub implementations of the API interfaces (written only when missing; default: `true`) |
| `skip_deprecated` | `true`, `false` | Don't generate deprecated operations (default: `false`) |
| `skip_disabled` | `true`, `false` | Don't generate operations disabled with the `x-apigenie` extension (default: `true`) |
| `model_suffix` | text | Suffix of model names, e.g. `Dto` |
| `version` | version | Version of the project (also `--package-version`); defaults to the version of the API |

Unknown options are errors.
