Example of an ASP.NET Core API.
Repo features:
- Initialisation script for quick namespace adjustment.
- Use of NSwag to automatically document endpoints and to generate client code for
an interop package.
- Recommended next step: Exporting the interop package as a NuGet for use in other projects.
- Roslyn source generation for MariaDB/Dapper data-access scaffolding (services,
repositories, search requests, and related DI) from annotated DTO models.
- This is demonstrated in the implementation for accessing the
Orderdata store.
- This is demonstrated in the implementation for accessing the
- Configurable rate limiting using a sliding window system:
- Uses either Redis or in-memory for storing limits.
- JWT bearer authentication (optional; Keycloak in the local Compose stack).
- Example connectors to secondary APIs
- The "Foo" connector connects to the imaginary Foo API using a static key.
- The "Bar" connector connects to the imaginary Foo API using a bearer token obtained using a OAuth Client Credentials request.
- Configuration is based on environment variables.
Database DDL for this API lives in a separate repository: RedShirt.Example.Schema.
That project owns MariaDB/MySQL schema versioning (using the DbUp library to apply incremental SQL scripts). This API
assumes those tables already exist and does not create or migrate them. The intent of this dedicated schema was to
enforce separation of concerns and prevent the API from having the power to affect the schema on a fundamental level.
When developing against the local Compose stack, apply schema updates from the Schema repo before starting the API (see
test/local/).
To change the namespace of the API en-masse for your purposes, use the init-repo.sh script:
bash init-repo.sh New.Namespace.HereThis API is expected to be run out of a docker container, so it relies on environment variables for most of its configuration.
For configuration examples, see the api section of the test/local/docker-compose.yaml file.
This API is built with the option for rate limiting, using a sliding window system backed either by Redis or an in-memory system.
To make use of rate limiting, you must either:
- Use the
[EnableRateLimiting("example")]attribute to name a policy (unlike the example on this list item, using constants for this is strongly encouraged). - Set and configure a default policy to require rate limiting across all endpoints (unless ruled out by the use of the
[DisableRateLimiting]attribute applied to an endpoint or controller).
Resources:
- For configuration examples, see the
apisection of thetest/local/docker-compose.yamlfile. Rate limiting is defined in environment variables beginning inRATE_LIMITING. - To better understand the configuration definitions, refer to the classes in the
Configuration/folder of theCommon.RateLimitingproject
Tips for local development.
If you are developing new features for source generation, you may find that the standard build for solution or the ASP.NET subproject does not express errors in the generation very well. Generally, it shall only print the exception message with no further context.
The way around this is to print out the compiler's SARIF logs:
dotnet build src/RedShirt.Example.Api.Implementations.Orders/RedShirt.Example.Api.Implementations.Orders.csproj \
/p:ErrorLog=compiler-diagnostics.sarif.log
find . -name '*sarif.log'The stack trace should be in the logs for the project that you targeted:
less ./src/RedShirt.Example.Api.Implementations.Orders/compiler-diagnostics.sarif.logIf the build does not show up, run dotnet clean to ensure a fresh build:
dotnet cleanGenerated files typically show up in a C# project under Dependencies / .NET / Source Generators. If this Source Generators folder is not showing up and the source generator phase of the build appears to be working, then you may need to click the UI button for Restart Roslyn Analyzers and Source Generators. In JetBrains Rider, it can be found at It can be found as an item in the Rosalyn Analyzers menu in the bottom-right of the main window. I can only describe the Rosalyn logo as "a weird branch-y thing".
For local testing, see the test/local folder. That guide covers bringing up MariaDB and applying schema updates via
RedShirt.Example.Schema.
Rough citation of some sources beyond memory.
- RicoSuter/NSwag#2409 - on models not showing up
- https://github.com/RicoSuter/NSwag/wiki/NSwag.MSBuild
- https://stackoverflow.com/questions/33283071/swagger-webapi-create-json-on-build
- https://github.com/RicoSuter/NSwag/wiki/CommandLine/ce950c5aea7bf52a85ec6e517ad8ea96762181ed
- RicoSuter/NSwag#1573
- Should use aspnetcore2swagger
- RicoSuter/NSwag#3119
- Use nobuild to avoid infinite build loop
- https://github.com/RicoSuter/NSwag/wiki/NSwag-Configuration-Document
- Doesn't include sourcing from an existing swagger.json though...
- Derived 'Net80' runtime from phrasing in EXE variable
- https://stackoverflow.com/questions/63791017/generate-with-nswag-an-openapi-document-including-swashbuckle-custom-operation-f
- Describes fromDocument section
- Derive from Url, but we want path
- https://stackoverflow.com/questions/73016248/generating-c-sharp-api-client-with-nswag-msbuild\
- Derive from Json
- https://stackoverflow.com/questions/59393267/generate-nswag-client-as-part-of-the-build
- Mentions rigging up before build
- https://github.com/RicoSuter/NSwag/wiki/AspNetCoreOpenApiDocumentGenerator
- https://github.com/RicoSuter/NSwag/blob/master/src/NSwag.Commands/Commands/Generation/AspNetCore/AspNetCoreToOpenApiCommand.cs
- https://github.com/RicoSuter/NSwag/blob/master/src/NSwag.Commands/Commands/OutputCommandBase.cs