### Enable Job Queues in Application Startup Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...14]job-queues.md Configure job queues by adding services and middleware during application startup. This example shows the basic setup in program.cs. ```csharp var bld = WebApplication.CreateBuilder(); bld.Services .AddFastEndpoints() .AddJobQueues(); //ignore generic arguments for now var app = bld.Build(); app.UseFastEndpoints(); app.UseJobQueues(); app.Run(); ``` -------------------------------- ### Shorthand Route Configuration (GET) Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...20]misc-conveniences.md Use shorthand methods like Get(), Post(), Put(), Patch(), and Delete() for combined verb and route configuration. This example configures a GET endpoint for a specific customer route. ```csharp public override void Configure() { Get("/api/customer/{CustomerID}"); } ``` -------------------------------- ### Install FastEndpoints.AspVersioning Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Install the necessary wrapper library from NuGet using the Package Manager Console. ```sh Install-Package FastEndpoints.AspVersioning ``` -------------------------------- ### Install and Scaffold FastEndpoints Project Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...18]integration-unit-testing.md Use these commands to install the FastEndpoints.TemplatePack and scaffold a new project for end-to-end testing. ```sh dotnet new install FastEndpoints.TemplatePack dotnet new feproj -n E2EWalkthrough ``` -------------------------------- ### Install FastEndpoints.Swagger Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Install the necessary NuGet package to enable Swagger support. ```bash dotnet add package FastEndpoints.Swagger ``` -------------------------------- ### Add Multiple Request Examples Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Specify multiple request examples by assigning to ExampleRequest multiple times or by adding to the RequestExamples collection. Each entry in RequestExamples can optionally include a label. ```csharp Summary(s => { s.ExampleRequest = new MyRequest {...}; s.ExampleRequest = new MyRequest {...}; s.RequestExamples.Add(new(new MyRequest { ... })); s.RequestExamples.Add(new(new MyRequest { ... }, "Example Label")); }); ``` -------------------------------- ### Install FastEndpoints.JobQueues NuGet Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...14]job-queues.md Install the FastEndpoints.JobQueues NuGet package using the .NET CLI if your project does not already reference the main FastEndpoints library. ```bash dotnet add package FastEndpoints.JobQueues ``` -------------------------------- ### Example Server Log Entry Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...17]exception-handler.md This is an example of a server log entry generated by the exception handler middleware. ```log fail: FastEndpoints.ExceptionHandler[0] ================================= HTTP: POST /inventory/adjust-stock TYPE: JsonException REASON: 'x' is an invalid start of a value. Path: $.ValMin | LineNumber: 4... --------------------------------- at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state,... at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader,... at System.Text.Json.JsonSerializer.ReadCore[TValue](JsonConverter jsonConverter,... ... ``` -------------------------------- ### Create Project and Install FastEndpoints Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...1]get-started.md Use the .NET CLI to create a new web application and add the FastEndpoints package. ```bash dotnet new web -n MyWebApp cd MyWebApp dotnet add package FastEndpoints ``` -------------------------------- ### Multiple Request Examples Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Adding multiple request examples to the Swagger documentation. ```APIDOC ## Multiple Request Examples ### Description Allows specifying multiple request examples by repeatedly setting `ExampleRequest` or by adding to the `RequestExamples` collection. ### Method N/A (Applies to any endpoint using `Summary()`) ### Endpoint N/A ### Parameters None ### Request Example ```json { "example": "MyRequest {...}" } ``` ### Response N/A ### Code Example ```cs Summary(s => { s.ExampleRequest = new MyRequest {...}; s.ExampleRequest = new MyRequest {...}; s.RequestExamples.Add(new(new MyRequest { ... })); s.RequestExamples.Add(new(new MyRequest { ... }, "Example Label")); }); ``` ``` -------------------------------- ### OData endpoints example Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...25]the-cookbook.md Example demonstrating the integration of OData endpoints within the FastEndpoints framework. This snippet shows how to enable and configure OData support. ```csharp using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.OData; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(); builder.Services.AddFastEndpoints() .AddOData(options => { options.Select().Filter().OrderBy().Expand().Count().SkipToken(); }); builder.Services.AddControllersWithViews().AddNewtonsoftJson(); builder.Services.AddOData(options => { options.Select().Filter().OrderBy().Expand().Count().SkipToken(); }); var app = builder.Build(); app.UseHttpsRedirection(); app.UseODataRouteComponents("odata", typeof(Program)); app.MapControllers(); app.Run(); ``` -------------------------------- ### Constructor Injection Example Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...5]dependency-injection.md Demonstrates constructor injection of IHelloWorldService in an endpoint. ```csharp public class MyEndpoint : EndpointWithoutRequest { private IHelloWorldService _helloService; public MyEndpoint(IHelloWorldService helloScv) { _helloService = helloScv; } public override void Configure() { Get("/api/hello-world"); } public override async Task HandleAsync(CancellationToken ct) { await Send.OkAsync(_helloService.SayHello()); } } ``` -------------------------------- ### Configure Endpoint Summary and Description Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Configure endpoint summaries, descriptions, example requests, and response details directly within the Configure method using the Summary() extension. Note that only one response example can be specified per status code. ```csharp public override void Configure() { Post("/item/create"); Description(b => b.Produces(403)); Summary(s => { s.Summary = "short summary goes here"; s.Description = "long description goes here"; s.ExampleRequest = new MyRequest {...}; s.ResponseExamples[200] = new MyResponse {...}; s.Responses[200] = "ok response description goes here"; s.Responses[403] = "forbidden response description goes here"; }); } ``` -------------------------------- ### Simplify Swagger Setup for Development Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...23]native-aot.md Configure project settings to simplify Swagger setup for development builds. This configuration is still needed for swagger generation in release builds. ```xml true true true Generated/SerializerCtx ``` -------------------------------- ### HTTP Request Example Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Illustrates an HTTP request with route and JSON body data. ```yaml route: /api/user/{UserID} url: /api/user/54321 json: { "UserID": "12345" } ``` -------------------------------- ### Endpoint Versioning with Starting Release and Deprecation Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Configure an endpoint to start appearing from a specific release version and to be deprecated at a later version. This combines both starting release and deprecation logic. ```cs public override void Configure() { Version(1) .StartingRelease(2) .DeprecateAt(4); } ``` -------------------------------- ### Using Pre-Resolved Services Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...5]dependency-injection.md Example of accessing pre-resolved services like IConfiguration, IWebHostEnvironment, and ILogger within an endpoint handler. ```csharp public override async Task HandleAsync(CancellationToken ct) { Logger.LogInformation("this is a log message"); var isProduction = Env.IsProduction(); var smtpServer = Config["SMTP:HostName"]; } ``` -------------------------------- ### Install Build Tools on Linux Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...23]native-aot.md Install the necessary dependencies for Native AOT compilation on various Linux distributions. ```ini # Arch sudo pacman -S --needed base-devel clang zlib krb5 icu # Debian sudo apt-get install clang zlib1g-dev # Alpine sudo apk add clang build-base zlib-dev # Fedora/RHEL sudo dnf install clang zlib-devel zlib-ng-devel zlib-ng-compat-devel ``` -------------------------------- ### Install FastEndpoints Template Pack Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...24]scaffolding.md Install the FastEndpoints template pack using the dotnet CLI. This enables the 'feat' command for creating new feature file sets. ```sh dotnet new install FastEndpoints.TemplatePack ``` -------------------------------- ### Implement Open-Generic Command Middleware Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...13]command-bus.md Implement the ICommandMiddleware interface for open-generic middleware. This example demonstrates logging before and after command execution. ```csharp sealed class CommandLogger(ILogger logger) : ICommandMiddleware where TCommand : ICommand { public async Task ExecuteAsync(TCommand command, CommandDelegate next, CancellationToken ct) { logger.LogInformation("Executing command: {name}", command.GetType().Name); var result = await next(); logger.LogInformation("Got result: {value}", result); return result; } } ``` -------------------------------- ### Scaffold Bare-Bones Starter Project Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...24]scaffolding.md Creates a new FastEndpoints starter project with a traditional integration testing setup using xUnit. Use the -n flag to specify the project name. ```bash dotnet new feproj -n MyAwesomeProject ``` -------------------------------- ### Basic Swagger Setup in Program.cs Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Add Swagger support to your FastEndpoints application by registering services and middleware. Visit /swagger for UI and /swagger/v1/swagger.json for the JSON document. ```csharp using FastEndpoints; using FastEndpoints.Swagger; //add this var bld = WebApplication.CreateBuilder(); bld.Services .AddFastEndpoints() .SwaggerDocument(); //define a swagger document var app = bld.Build(); app.UseFastEndpoints() .UseSwaggerGen(); //add this app.Run(); ``` -------------------------------- ### Example Idempotent GET Request with Curl Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...22]idempotency.md Send a GET request to an idempotent endpoint including the 'Idempotency-Key' header with a unique value. ```bash curl -X 'GET' \ 'http://localhost:5000/my-endpoint' \ -H 'accept: text/plain' \ -H 'idempotency-key: 1dc3d9a8527047069f8056175a71fe79' ``` -------------------------------- ### Add FastEndpoints Security Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...2]security.md Install the FastEndpoints.Security package using the .NET CLI. ```bash dotnet add package FastEndpoints.Security ``` -------------------------------- ### Example JSON Response Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...17]exception-handler.md This is an example of the JSON response returned to the client for an internal server error. ```json { "Status": "Internal Server Error!", "Code": 500, "Reason": "'x' is an invalid start of a value. Path: $.ValMin | LineNumber: 4...", "Note": "See application log for stack trace." } ``` -------------------------------- ### Property Injection Example Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...5]dependency-injection.md Demonstrates how to inject IHelloWorldService using property injection in an endpoint. ```csharp public class MyEndpoint : EndpointWithoutRequest { public IHelloWorldService HelloService { get; set; } public override void Configure() { Get("/api/hello-world"); } public override async Task HandleAsync(CancellationToken ct) { await Send.OkAsync(HelloService.SayHello()); } } ``` -------------------------------- ### Endpoint Starting Release Configuration Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Define the starting release version for an endpoint. Endpoints configured this way will only appear in Swagger docs for the specified release version and newer. ```cs public override void Configure() { Version(1).StartingRelease(2); } ``` -------------------------------- ### Install FastEndpoints.ClientGen.Kiota Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Add the FastEndpoints.ClientGen.Kiota NuGet package to your project to integrate API client generation into your FastEndpoints application. ```bash dotnet add package FastEndpoints.ClientGen.Kiota ``` -------------------------------- ### Swagger Documentation with Summary Method Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Configuring Swagger summaries, descriptions, and examples directly within the endpoint's Configure method. ```APIDOC ## Swagger Documentation with Summary Method ### Description Specifies summary and description text for endpoint responses, along with example request and response objects using the `Summary()` method. ### Method POST ### Endpoint /item/create ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (Implicitly defined by `MyRequest` in example) ### Request Example ```json { "example": "MyRequest {...}" } ``` ### Response #### Success Response (200) - **description** (string) - ok response description goes here #### Forbidden Response (403) - **description** (string) - forbidden response description goes here #### Response Example ```json { "example": "MyResponse {...}" } ``` ### Code Example ```cs public override void Configure() { Post("/item/create"); Description(b => b.Produces(403)); Summary(s => { s.Summary = "short summary goes here"; s.Description = "long description goes here"; s.ExampleRequest = new MyRequest {...}; s.ResponseExamples[200] = new MyResponse {...}; s.Responses[200] = "ok response description goes here"; s.Responses[403] = "forbidden response description goes here"; }); } ``` ``` -------------------------------- ### Add FastEndpoints Packages to Existing Project Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...23]native-aot.md Install the necessary FastEndpoints NuGet packages for a new or existing web project. ```sh dotnet new web -n MyWebApp cd MyWebApp dotnet add package FastEndpoints dotnet add package FastEndpoints.Generator dotnet add package FastEndpoints.Swagger dotnet add package Scalar.AspNetCore ``` -------------------------------- ### Setup Event Publisher (gRPC Server) Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...15]remote-procedure-calls.md Configure the gRPC server to register an event hub for a specific event type. This involves setting up Kestrel, adding handler server capabilities, and mapping event hubs. ```csharp var bld = WebApplication.CreateBuilder(); bld.WebHost.ConfigureKestrel(o => o.ListenLocalhost(6000, o => o.Protocols = HttpProtocols.Http2)); bld.AddHandlerServer(); var app = bld.Build(); app.MapHandlers(h => { h.RegisterEventHub(); }); app.Run() ``` -------------------------------- ### Example Response Body Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...1]get-started.md The expected JSON response after a successful POST request. ```json { "FullName": "Marlon Brando", "IsOver18": true } ``` -------------------------------- ### Example POST Request Body Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...1]get-started.md Send a POST request to the /api/user/create endpoint with this JSON body. ```json { "FirstName": "Marlon", "LastName": "Brando", "Age": 40 } ``` -------------------------------- ### Request DTO Example Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md A simple C# DTO for receiving user ID. ```csharp public class GetUserRequest { public string UserID { get; set; } } ``` -------------------------------- ### Configure and Use Event Bus in Console App Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...12]event-bus.md Register messaging services with the IOC container using AddMessaging() and configure them with UseMessaging(). This example demonstrates publishing an AppStarted event and handling it. ```csharp using FastEndpoints; //add this using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; var bld = Host.CreateApplicationBuilder(); bld.Services.AddMessaging(); //add this var host = bld.Build(); host.Services.UseMessaging(); //add this var appStartedEvent = new AppStarted(); await appStartedEvent.PublishAsync(); await host.RunAsync(); sealed class AppStarted : IEvent { public string Message => "Welcome to the App!"; } sealed class AppStartedHandler(ILogger logger) : IEventHandler { public Task HandleAsync(AppStarted e, CancellationToken c) { logger.LogInformation("{@msg}", e.Message); return Task.CompletedTask; } } ``` -------------------------------- ### Generic Request Logger Pre-Processor Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...11]pre-post-processors.md Example implementation of a generic pre-processor that logs requests. It must implement IPreProcessor. ```csharp sealed class RequestLogger : IPreProcessor { public Task PreProcessAsync(IPreProcessorContext ctx, CancellationToken c) { ... } } ``` -------------------------------- ### Publish Events Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...15]remote-procedure-calls.md Publish events to be broadcast to subscribers. This example creates and broadcasts a 'SomethingHappened' event. ```cs new SomethingHappened { Id = 1, Description = "I am a test event!" } .Broadcast(); ``` -------------------------------- ### Register and Use Messaging Services Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...13]command-bus.md Register messaging services with the IOC container using AddMessaging() and then use them with UseMessaging(). This example demonstrates a simple command execution. ```csharp using FastEndpoints; //add this using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; var bld = Host.CreateApplicationBuilder(); bld.Services.AddMessaging(); //add this var host = bld.Build(); host.Services.UseMessaging(); //add this var greetUser = new GreetUser(); await greetUser.ExecuteAsync(); await host.RunAsync(); sealed class GreetUser : ICommand { public string Message => "Welcome to the App!"; } sealed class GreetUserHandler(ILogger logger) : ICommandHandler { public Task ExecuteAsync(GreetUser e, CancellationToken c) { logger.LogInformation("{@msg}", e.Message); return Task.CompletedTask; } } ``` -------------------------------- ### Execute a Command Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...13]command-bus.md Execute a command by calling the ExecuteAsync() extension method on the command object. This example executes the GetFullName command. ```csharp var fullName = await new GetFullName() { FirstName = "john", LastName = "snow" } .ExecuteAsync(); ``` -------------------------------- ### Add FastEndpoints.Messaging Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...12]event-bus.md Install the FastEndpoints.Messaging NuGet package to use the event bus independently of the FastEndpoints framework. ```shell dotnet add package FastEndpoints.Messaging ``` -------------------------------- ### Job storage provider with Dapper Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...25]the-cookbook.md Example of implementing a job storage provider using Dapper for persistence. This snippet demonstrates how to integrate Dapper with FastEndpoints for managing job storage records. ```csharp using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading; using System.Threading.Tasks; using Dapper; using FastEndpoints.JobManager; using Microsoft.Data.SqlClient; namespace Application.Jobs; public class JobStorageProvider : IJobStorageRecord { private readonly string _connStr; public JobStorageProvider(string connStr) { _connStr = connStr; } public async Task GetJob(Guid jobId, CancellationToken cancellationToken = default) { await using var db = new SqlConnection(_connStr); var record = await db.QuerySingleOrDefaultAsync( "SELECT * FROM JobStorage WHERE JobId = @JobId", new { JobId = jobId }); return record; } public async Task> GetJobs(CancellationToken cancellationToken = default) { await using var db = new SqlConnection(_connStr); return await db.QueryAsync("SELECT * FROM JobStorage"); } public async Task SaveJob(JobStorageRecord record, CancellationToken cancellationToken = default) { await using var db = new SqlConnection(_connStr); await db.ExecuteAsync( "MERGE INTO JobStorage AS target USING (VALUES (@JobId, @JobState, @LastUpdated, @NextRun, @Data)) AS source (JobId, JobState, LastUpdated, NextRun, Data) ON target.JobId = source.JobId WHEN MATCHED THEN UPDATE SET JobState = source.JobState, LastUpdated = source.LastUpdated, NextRun = source.NextRun, Data = source.Data WHEN NOT MATCHED THEN INSERT (JobId, JobState, LastUpdated, NextRun, Data) VALUES (source.JobId, source.JobState, source.LastUpdated, source.NextRun, source.Data);", new { JobId = record.JobId, JobState = record.JobState, LastUpdated = record.LastUpdated, NextRun = record.NextRun, Data = record.Data }); return record; } public async Task DeleteJob(Guid jobId, CancellationToken cancellationToken = default) { await using var db = new SqlConnection(_connStr); await db.ExecuteAsync("DELETE FROM JobStorage WHERE JobId = @JobId", new { JobId = jobId }); } } ``` -------------------------------- ### Configure FastEndpoints with Swagger and OpenApi Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...23]native-aot.md Set up FastEndpoints services, configure Swagger documentation settings, and enable the OpenApi middleware. This snippet demonstrates the basic setup for integrating FastEndpoints with Swagger and OpenApi. ```csharp var bld = WebApplication.CreateSlimBuilder(args); bld.Services .AddFastEndpoints(...) .SwaggerDocument( o => o.DocumentSettings = d => { d.DocumentName = "v1"; }); var app = bld.Build(); app.UseFastEndpoints(...) .UseOpenApi(c => c.Path = "/openapi/{documentName}.json"); app.MapScalarApiReference(o => o.AddDocument("v1")); app.Run(); ``` -------------------------------- ### Create an AppFixture Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...18]integration-unit-testing.md Inherit from AppFixture to create a custom fixture. Override SetupAsync, ConfigureApp, ConfigureServices, and TearDownAsync for custom setup, configuration, service registration, and cleanup. ```csharp public class MyApp : AppFixture { protected override ValueTask SetupAsync() { // place one-time setup code here } protected override void ConfigureApp(IWebHostBuilder a) { // do host builder config here } protected override void ConfigureServices(IServiceCollection s) { // do test service registration here } protected override ValueTask TearDownAsync() { // do cleanups here } } ``` -------------------------------- ### Add FastEndpoints Generator Package Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...19]configuration-settings.md Install the FastEndpoints.Generator NuGet package to enable source generation. This is the first step to utilizing the source generator features. ```sh dotnet add package FastEndpoints.Generator ``` -------------------------------- ### Implement Event Handler Interface Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...15]remote-procedure-calls.md Implement the IEventHandler interface to create a handler for specific events. This example shows how to log event details. ```cs internal class WhenSomethingHappens : IEventHandler { private readonly ILogger _logger; public WhenSomethingHappens(ILogger logger) { _logger = logger; } public Task HandleAsync(SomethingHappened evnt, CancellationToken ct) { _logger.LogInformation("{number} - {description}", evnt.Id, evnt.Description); return Task.CompletedTask; } } ``` -------------------------------- ### Configure Startup with FastEndpoints Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...1]get-started.md Replace the contents of Program.cs to include FastEndpoints services and middleware. ```csharp using FastEndpoints; var bld = WebApplication.CreateBuilder(); bld.Services.AddFastEndpoints(); var app = bld.Build(); app.UseFastEndpoints(); app.Run(); ``` -------------------------------- ### Binding Route Parameters to DTO Properties Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Route parameters can be bound to DTO properties by defining them in the route template. The example shows binding various primitive types from a GET request URL to a `MyRequest` DTO. ```csharp public class MyRequest { public string MyString { get; set; } public bool MyBool { get; set; } public int MyInt { get; set; } public long MyLong { get; set; } public double MyDouble { get; set; } public decimal MyDecimal { get; set; } } ``` ```csharp public class MyEndpoint : Endpoint { public override void Configure() { Get("/api/{MyString}/{MyBool}/{MyInt}/{MyLong}/{MyDouble}/{MyDecimal}"); } } ``` -------------------------------- ### Publish Event as Extension Method Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...12]event-bus.md Publish an event directly from any class by implementing the IEvent interface and using the PublishAsync extension method. This example demonstrates publishing with Mode.WaitForAll. ```csharp public class OrderCreatedEvent : IEvent { ... } ``` ```csharp await new OrderCreatedEvent { OrderID = "12345", CustomerName = "scarlet johanson", OrderTotal = 123.45m } .PublishAsync(Mode.WaitForAll); ``` -------------------------------- ### Custom Global Request Binder Implementation Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Implement the IRequestBinder interface to create a custom request binder that can be registered globally. This example demonstrates deserializing JSON content and setting a TenantId from headers. ```cs public class MyRequestBinder : IRequestBinder where TRequest : notnull, new() { public async ValueTask BindAsync(BinderContext ctx, CancellationToken ct) { if (ctx.HttpContext.Request.HasJsonContentType()) { var req = await JsonSerializer.DeserializeAsync( ctx.HttpContext.Request.Body, ctx.SerializerOptions, ct); if (req is IHasTenantId r) r.TenantId = ctx.HttpContext.Request.Headers["x-tenant-id"]; return req!; } return new(); } } ``` -------------------------------- ### Example Problem Details JSON Response Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...19]configuration-settings.md An example of an RFC7807/RFC9457 compatible JSON response for validation errors. ```json { "type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "instance": "/api/test/666", "traceId": "0HMPNHL0JHL76:00000001", "errors": [ { "name": "clientIP", "reason": "IP address is blocked!" }, { "name": "clientID", "reason": "Invalid client ID!" } ] } ``` -------------------------------- ### Build Project for Generator to Run Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Perform an initial build after enabling source generation for the generator to execute and create the necessary serializer contexts. ```shell dotnet build ``` -------------------------------- ### Create JWT Login Endpoint Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...2]security.md An example login endpoint that issues an initial pair of access and refresh tokens using a custom token service. User credential checking is omitted for brevity. ```cs public class LoginEndpoint : EndpointWithoutRequest { public override void Configure() { Get("/api/login"); AllowAnonymous(); } public override async Task HandleAsync(CancellationToken c) { //user credential checking has been omitted for brevity Response = await CreateTokenWith("user-id-001", u => { u.Roles.AddRange(new[] { "Admin", "Manager" }); u.Permissions.Add("Update_Something"); u.Claims.Add(new("UserId", "user-id-001")); }); } } ``` -------------------------------- ### Configure Persistent Event Hub with Known Subscriber IDs Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...15]remote-procedure-calls.md Configure a persistent event hub to start storing events for known subscribers from application startup, even if they are not yet connected. This requires matching subscriber IDs on both client and hub. ```cs app.MapHandlers(h => { h.RegisterEventHub(["worker-a", "worker-b"]); }); ``` -------------------------------- ### Configure Client/Channel Options Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...15]remote-procedure-calls.md Specify GrpcChannelOptions at startup to configure client behavior, such as retry attempts and HTTP handlers. ```csharp app.MapRemote("http://localhost:6000", c => { c.ChannelOptions.MaxRetryAttempts = 5; c.ChannelOptions.HttpHandler = new() { ... }; c.ChannelOptions.ServiceConfig = new() { ... }; }); ``` -------------------------------- ### Register Newtonsoft JSON Converters for Swagger Examples Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Registers Newtonsoft JSON converters for use by the FastEndpoints NSwag processor when serializing example requests/responses. Note that these are not used by NSwag for schema generation. ```csharp bld.Services.SwaggerDocument(o => { o.NewtonsoftSettings = s => { s.Converters.Add(new MyJsonConverter()); }; }); ``` -------------------------------- ### Register Custom Guid Value Parser Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Register a custom value parser for Guid types to handle parsing from various sources. This parser takes precedence over the static TryParse method for non-JSON operations. ```cs app.UseFastEndpoints(c => { c.Binding.ValueParserFor(MyParsers.GuidParser); }); public static class MyParsers { public static ParseResult GuidParser(object? input) { bool success = Guid.TryParse(input?.ToString(), out var result); return new (success, result); } } ``` -------------------------------- ### Configure Slim Builder and Type Discovery Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...23]native-aot.md Use `CreateSlimBuilder` and configure `AddFastEndpoints` to use `DiscoveredTypes.All` for source generator discovered types in your `Program.cs`. ```csharp var bld = WebApplication.CreateSlimBuilder(args); bld.Services.AddFastEndpoints(o => o.SourceGeneratorDiscoveredTypes = DiscoveredTypes.All) ``` -------------------------------- ### Define HelloWorldService Interface and Implementation Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...5]dependency-injection.md Defines the service interface and its concrete implementation for dependency injection. ```csharp public interface IHelloWorldService { string SayHello(); } public class HelloWorldService : IHelloWorldService { public string SayHello() => "hello world!"; } ``` -------------------------------- ### FastEndpoints Feature Help Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...24]scaffolding.md Displays available options for the FastEndpoints feature file generation command. ```bash > dotnet new feat --help FastEndpoints Feature Fileset (C#) Options: -t|--attributes Whether to use attributes for endpoint configuration bool - Optional Default: false -p|--mapper Whether to use a mapper bool - Optional Default: true -v|--validator Whether to use a validator bool - Optional Default: true -m|--method Endpoint HTTP method GET POST PUT DELETE PATCH Default: GET -r|--route Endpoint path string - Optional Default: api/route/here ``` -------------------------------- ### JSON Body for [FromBody] Property Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Example JSON request body that maps to a DTO decorated with [FromBody]. ```json { "Street": "123 road", "City": "new york", "Country": "usa" } ``` -------------------------------- ### Configure Cookie Authentication in Program.cs Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...2]security.md Sets up cookie authentication with HTTP-only and SameSite=Lax attributes. Ensure to add the necessary using statement for FastEndpoints.Security. ```cs using FastEndpoints; using FastEndpoints.Security; //add this var bld = WebApplication.CreateBuilder(); bld.Services .AddAuthenticationCookie(validFor: TimeSpan.FromMinutes(10)) //configure cookie auth .AddAuthorization() //add this .AddFastEndpoints(); var app = bld.Build(); app.UseAuthentication() //add this .UseAuthorization() //add this .UseFastEndpoints(); app.Run(); ``` -------------------------------- ### Endpoint with EmptyRequest and EmptyResponse Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...1]get-started.md Example of defining an endpoint that does not expect a request body and does not return a response body. ```csharp public class MyEndpoint : Endpoint { } ``` -------------------------------- ### SvelteKit Static Adapter Configuration Source: https://context7.com/fastendpoints/documentation/llms.txt Configures SvelteKit for static site generation, including markdown file support and prerendering. Use this to set up the build process for a static deployment. ```javascript // svelte.config.js import adapter from '@sveltejs/adapter-static'; import preprocess from 'svelte-preprocess'; const config = { extensions: ['.svelte', '.md'], kit: { adapter: adapter({ pages: 'docs', assets: 'docs' }), prerender: { default: true, entries: ['*'] } }, preprocess: preprocess({ postcss: true }) }; export default config; // Build commands (package.json): // npm run dev - Start development server // npm run build - Build static site to ./docs directory // npm run preview - Preview built site locally ``` -------------------------------- ### Configure Persistent Event Hub with Custom Storage Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...15]remote-procedure-calls.md Set up event handling with persistence by specifying custom storage record and provider implementations. This ensures events are not lost during exceptional circumstances. ```cs app.MapHandlers(h => { h.RegisterEventHub(); }); ``` -------------------------------- ### Scaffold xUnit Test Project Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...24]scaffolding.md Creates a new xUnit integration testing project for FastEndpoints. This command does not require a project name argument. ```bash dotnet new fetest ``` -------------------------------- ### Enable Versioning in FastEndpoints Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Configure versioning by setting a prefix during FastEndpoints startup. The prefix is used to create versioned routes like 'v1'. ```csharp app.UseFastEndpoints(c => { c.Versioning.Prefix = "v"; }); ``` -------------------------------- ### Execute Generic Commands Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...13]command-bus.md Execute generic commands after they have been registered. These examples show executing MyCommand with different generic type arguments. ```csharp var results = await new MyCommand().ExecuteAsync(); var results = await new MyCommand().ExecuteAsync(); ``` -------------------------------- ### Associate Endpoints with Version Sets (v2) Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Map a GET endpoint for '/order/invoices' to the '>>Orders<<' version set and API version 2.0. ```cs public class GetInvoices_v2 : EndpointWithoutRequest { public override void Configure() { Get("/order/invoices"); Options(x => x .WithVersionSet(">>Orders<<") .MapToApiVersion(2.0)); } public override async Task HandleAsync(CancellationToken c) { await Send.OkAsync("v2 - orders"); } } ``` -------------------------------- ### Register Open-Generic Command Middleware Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...13]command-bus.md Register open-generic middleware components in the desired execution order using the AddCommandMiddleware extension method. ```csharp bld.Services.AddCommandMiddleware( c => { c.Register(typeof(CommandLogger<,>), typeof(CommandValidator<,>), typeof(ResultLogger<,>)); }); ``` -------------------------------- ### Configure Pre-configured HttpClients in Fixture Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...18]integration-unit-testing.md Set up pre-configured HttpClient instances on the AppFixture itself for reuse across multiple test methods. Ensure clients are disposed of properly. ```csharp using FastEndpoints.Testing; using System.Net.Http; using System.Threading.Tasks; public class MyApp : AppFixture { public HttpClient Admin { get; private set; } public HttpClient Customer { get; private set; } protected override async ValueTask SetupAsync() { // Assume GetApiKey is a method available in AppFixture or defined elsewhere var apiKey = await GetApiKey(...); Admin = CreateClient(c => c.DefaultRequestHeaders.Add("x-api-key", apiKey)); Customer = CreateClient(); } protected override ValueTask TearDownAsync() { Admin.Dispose(); Customer.Dispose(); return ValueTask.CompletedTask; } } ``` -------------------------------- ### Associate Endpoints with Version Sets (v1) Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Map a GET endpoint for '/orders/invoices' to the '>>Orders<<' version set and API version 1.0. ```cs public class GetInvoices_v1 : EndpointWithoutRequest { public override void Configure() { Get("/orders/invoices"); Options(x => x .WithVersionSet(">>Orders<<") .MapToApiVersion(1.0)); } public override async Task HandleAsync(CancellationToken c) { await Send.OkAsync("v1 - orders"); } } ``` -------------------------------- ### Enable Versioning Middleware Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Configure the services to enable API versioning, setting the default API version and specifying the header for reading the version. ```cs bld.Services .AddFastEndpoints() .AddVersioning(o => { o.DefaultApiVersion = new(1.0); o.AssumeDefaultVersionWhenUnspecified = true; o.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version"); }) ``` -------------------------------- ### Enable Response Caching Middleware Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...8]response-caching.md Add the response caching services and middleware to your application pipeline. This setup is required before FastEndpoints is used. ```csharp var bld = WebApplication.CreateBuilder(); bld.Services .AddFastEndpoints() .AddResponseCaching(); //add this var app = bld.Build(); app.UseResponseCaching() //add this before FE .UseFastEndpoints(); app.Run(); ``` -------------------------------- ### State-Aware Age Checker Pre-Processor Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...11]pre-post-processors.md An example pre-processor that checks age and updates a shared state bag. It inherits from PreProcessor. ```csharp public class AgeChecker : PreProcessor { public override Task PreProcessAsync(IPreProcessorContext ctx, MyStateBag state) { if (ctx.Request.Age >= 18) state.IsValidAge = true; state.Status = $"age checked by pre-processor at {state.DurationMillis} ms."; return Task.CompletedTask; } } ``` -------------------------------- ### Registering Custom JSON Converters Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Shows how to register custom System.Text.Json converters during FastEndpoints startup. ```csharp app.UseFastEndpoints(c => { c.Serializer.Options.Converters.Add(new CustomConverter()); }); ``` -------------------------------- ### Configure Global Endpoint Options Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...19]configuration-settings.md Apply common settings to endpoints based on their routes during application startup. Inspect the EndpointDefinition to modify endpoint behavior. ```csharp app.UseFastEndpoints(c => { c.Endpoints.Configurator = ep => { if (ep.Routes[0].StartsWith("/public") is true) { ep.AllowAnonymous(); ep.Options(b => b.RequireHost("www.domain.com")); ep.Description(b => b.Produces(400, "application/problem+json")); } }; }); ``` -------------------------------- ### Publish OrderCreatedEvent in Endpoint Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...12]event-bus.md Publish an event from within an endpoint's HandleAsync method. This example publishes an OrderCreatedEvent after creating a new order. ```csharp public class CreateOrderEndpoint : Endpoint { public override void Configure() { Post("/sales/orders/create"); } public override async Task HandleAsync(CreateOrderRequest req, CancellationToken ct) { var orderID = await orderRepo.CreateNewOrder(req); await PublishAsync(new OrderCreatedEvent { OrderID = orderID, CustomerName = req.Customer, OrderTotal = req.OrderValue }); await Send.OkAsync(); } } ``` -------------------------------- ### Enable XML Documentation in Project File Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Enable XML documentation generation by setting 'GenerateDocumentationFile' to true and 'NoWarn' to CS1591 in your .csproj file. This allows XML comments to be processed. ```xml true CS1591 ``` -------------------------------- ### Endpoint to Poll Job Progress Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...14]job-queues.md This endpoint retrieves job results using the tracking ID. It handles cases where the job hasn't started, is in progress, or has completed. ```csharp sealed class JobProgressEndpoint : EndpointWithoutRequest { public override void Configure() { Post("job/progress/{trackingId:guid}"); AllowAnonymous(); } public override async Task HandleAsync(CancellationToken c) { var trackingId = Route("trackingId"); var jobResult = await JobTracker .GetJobResultAsync>(trackingId, c); if (jobResult is null) { await Send.OkAsync("job execution hasn't begun yet!"); return; } switch (jobResult.IsComplete) { case false: await Send.OkAsync($"[{jobResult.ProgressPercentage}%] | status: {jobResult.CurrentStatus}"); break; case true: await Send.OkAsync($"end result: {jobResult.Result.MyMessage}"); break; } } } ``` -------------------------------- ### Configure JWT Token Creation Options Globally Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...2]security.md Configure JWT creation options globally using dependency injection. This allows specifying common settings like the signing key. ```csharp bld.Services.Configure( o => o.SigningKey = "..." ); ``` -------------------------------- ### Deprecate Endpoint by Version Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...21]api-versioning.md Mark an endpoint as deprecated starting from a specific version. Endpoints marked this way will be excluded from Swagger docs from the specified version onwards. ```cs Version(1, deprecateAt: 4); ``` -------------------------------- ### Generated Service Registration Extension Method Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...5]dependency-injection.md Example of a service registration extension method automatically generated by the FastEndpoints.Generator. The method name is derived from the assembly name. ```csharp public static class ServiceRegistrationExtensions { public static IServiceCollection RegisterServicesFromMyProject(this IServiceCollection sc) { sc.AddScoped(); ... } } ``` -------------------------------- ### Configure Endpoint Response Caching Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...8]response-caching.md Configure a specific endpoint to cache its response for a set duration using the ResponseCache() method. This example caches for 60 seconds. ```csharp public class MyEndpoint : EndpointWithoutRequest { public override void Configure() { Get("/api/cached-ticks"); ResponseCache(60); //cache for 60 seconds } public override Task HandleAsync(CancellationToken ct) { return Send.OkAsync(new { Message = "this response is cached" Ticks = DateTime.UtcNow.Ticks }); } } ``` -------------------------------- ### Use Custom Send Method in Endpoint Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...20]misc-conveniences.md Call custom send methods directly from your endpoint handler. This example demonstrates sending a custom status code. ```csharp public override async Task HandleAsync(Request r, CancellationToken ct) { await Send.StatusCode(219); } ``` -------------------------------- ### Configure Antiforgery Token Support Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...2]security.md Adds and configures antiforgery token support within the application's startup process. Ensure UseAntiforgeryFE() is called before UseFastEndpoints(). ```csharp using Microsoft.AspNetCore.Antiforgery; var bld = WebApplication.CreateBuilder(); bld.Services .AddFastEndpoints() .AddAntiforgery(); //add this var app = bld.Build(); app.UseAntiforgeryFE() //must come before UseFastEndpoints() .UseFastEndpoints(); app.Run(); ``` -------------------------------- ### Generate Clients to Disk via Command Line Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Generates API clients to disk when the application is run with a specific command-line argument. This is useful for CI/CD pipelines. Ensure the command-line arguments are passed to WebApplication.CreateBuilder. ```bash cd MyApp dotnet run --generateclients true ``` ```csharp var bld = WebApplication.CreateBuilder(args); //must pass in the args bld.Services .AddFastEndpoints() .SwaggerDocument(o => { o.DocumentSettings = s => s.DocumentName = "v1"; //must match doc name below }); var app = bld.Build(); app.UseFastEndpoints(); await app.GenerateApiClientsAndExitAsync( c => { c.SwaggerDocumentName = "v1"; //must match doc name above c.Language = GenerationLanguage.CSharp; c.OutputPath = Path.Combine(app.Environment.WebRootPath, "ApiClients", "CSharp"); c.ClientNamespaceName = "MyCompanyName"; c.ClientClassName = "MyCsClient"; c.CreateZipArchive = true; //if you'd like a zip file as well }, c => { c.SwaggerDocumentName = "v1"; c.Language = GenerationLanguage.TypeScript; c.OutputPath = Path.Combine(app.Environment.WebRootPath, "ApiClients", "Typescript"); c.ClientNamespaceName = "MyCompanyName"; c.ClientClassName = "MyTsClient"; }); app.Run(); ``` -------------------------------- ### Configure Endpoint Options Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...20]misc-conveniences.md Use the Options() method to customize aspects of endpoint registration like CORS policies, host requirements, and response production. ```csharp Options(b => b.RequireCors(x => x.AllowAnyOrigin()) .RequireHost("domain.com") .ProducesProblem(404)); ``` -------------------------------- ### Manually Create a Serializer Context Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...3]model-binding.md Define a partial class inheriting from JsonSerializerContext and decorate it with JsonSerializable attributes for each type that needs serialization. This is an example of creating a context for RequestModel and ResponseModel. ```csharp [JsonSerializable(typeof(RequestModel))] [JsonSerializable(typeof(ResponseModel))] public partial class UpdateAddressCtx : JsonSerializerContext { } ``` -------------------------------- ### Configure Endpoint Summary and Parameters Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...10]swagger-support.md Configure endpoint summaries and parameter descriptions using the Summary() method. This method allows overriding XML comments and defining descriptions for route parameters and request DTO properties. ```csharp public override void Configure() { Post("admin/login/{ClientID?}"); AllowAnonymous(); Summary(s => { s.Summary = "summary"; s.Description = "description"; s.Params["ClientID"] = "client id description"; s.RequestParam(r => r.UserName, "overriden username description"); }); } ``` -------------------------------- ### Response DTO Definition Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...1]get-started.md Define a response data transfer object (DTO) to structure the data returned by an endpoint. This example shows a simple DTO with `FullName` and `Age` properties. ```csharp public class MyResponse { public string FullName { get; set; } public int Age { get; set; } } ``` -------------------------------- ### Streaming JSON response with IAsyncEnumerable Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...25]the-cookbook.md Example of streaming JSON responses using IAsyncEnumerable. This is useful for large datasets or real-time data feeds where sending the entire response at once is inefficient. ```csharp using FastEndpoints; using Microsoft.AspNetCore.Mvc; public class StreamJsonEndpoint : EndpointWithoutRequest { public override async Task HandleAsync(CancellationToken ct) { Response.ContentType = "application/json"; await Response.WriteAsJsonAsync(GetData(), ct); } private async IAsyncEnumerable GetData() { for (var i = 0; i < 100; i++) { yield return i; await Task.Delay(100); // Simulate data generation delay } } } ``` -------------------------------- ### Add Discovered Types from Multiple Assemblies Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...19]configuration-settings.md When types are spread across multiple referenced projects, install the generator package in each and use 'AddRange()' to include discovered types from each assembly. ```cs bld.Services.AddFastEndpoints(o => { o.SourceGeneratorDiscoveredTypes.AddRange(MyApp.DiscoveredTypes.All); o.SourceGeneratorDiscoveredTypes.AddRange(SomeAssembly.DiscoveredTypes.All); }); ``` -------------------------------- ### Implement Global Pre-Processor for Tenant ID Source: https://github.com/fastendpoints/documentation/blob/main/src/routes/docs/[...11]pre-post-processors.md Create a global pre-processor to inject tenant information from headers into specific DTOs. This processor adds validation failures and sends errors if the tenant ID is missing. ```csharp public class TenantIDChecker : IGlobalPreProcessor { public async Task PreProcessAsync(IPreProcessorContext ctx, CancellationToken ct) { if (ctx.Request is MyRequest r) //can work on specific dto types if desired { var tID = ctx.HttpContext.Request.Headers["x-tenant-id"]; if (tID.Count > 0) { r.TenantID = tID[0]; } else { ctx.ValidationFailures.Add( new("TenantID", "Unable to retrieve tenant id from header!")); if (!ctx.HttpContext.ResponseStarted()) await ctx.HttpContext.Response.SendErrorsAsync(ctx.ValidationFailures); } } } } ```