Namespace Codebelt.Extensions.Carter
Build Carter-based ASP.NET Core minimal APIs with configurable response negotiation and endpoint metadata. The Codebelt.Extensions.Carter namespace gives you the infrastructure to plug content-aware response serialization into the Carter pipeline—letting HttpResponse.Negotiate() automatically select the right serializer based on the client's Accept header.
Use this namespace when you want to:
- Add OpenAPI/OpenAPI-like produces metadata to your endpoints using
Produces<TResponse>andProducesextension methods. - Build or integrate a custom response negotiator via
ConfigurableResponseNegotiator<TOptions>. - Choose from format-specific negotiator packages for JSON (Newtonsoft.Json or System.Text.Json), YAML, or XML.
Availability: .NET 10
Start here
For most applications, install one of the format-specific negotiator packages (e.g., Codebelt.Extensions.Carter.AspNetCore.Newtonsoft.Json) and register the negotiator in your Carter configuration via CarterConfigurator.WithResponseNegotiator<T>(). Then add produces metadata to your endpoints using the Produces<TResponse> extension method on IEndpointConventionBuilder.
If you need a custom serialization format, derive from ConfigurableResponseNegotiator<TOptions> in the Codebelt.Extensions.Carter.Response namespace and supply your own formatter.
Extension Members
| Type | Ext | Methods |
|---|---|---|
| IEndpointConventionBuilder | ⬇️ | Produces<TResponse>, Produces |
Classes
- EndpointConventionBuilderExtensions
-
Attach typed response metadata to any Carter or minimal API endpoint by calling
Produces<TResponse>orProduceson anIEndpointConventionBuilder. Each call records anIProducesResponseTypeMetadataentry that OpenAPI tooling reads to document the endpoint's response shape and status codes.Availability: .NET 10
Note: DocFX does not yet generate complete API metadata for C# 14 extension block members (docfx#11010). The extension methods themselves are fully functional; the limitation is cosmetic in generated API docs only.
Example
Produces<TResponse>andProducesattachIProducesResponseTypeMetadatadirectly to an endpoint builder.Produces<TResponse>records the response body type, HTTP status code, and accepted content types;Produces(no type parameter) records a status-only response with no body—useful for404,401, and similar cases. Both are chainable and are typically called on aRouteHandlerBuilderinside a Carter module or minimal API route definition.The following example constructs an endpoint builder directly, calls the extension members through their declaring type, and reads back the attached metadata to show what each call contributes:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Codebelt.Extensions.Carter; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Metadata; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Patterns; namespace DocfxExample; public static class ProducesExtensionExample { public static void Demonstrate() { var endpointBuilder = new RouteEndpointBuilder( context => Task.CompletedTask, RoutePatternFactory.Parse("/api/orders"), 0); var fakeBuilder = new FakeEndpointConventionBuilder(); EndpointConventionBuilderExtensions.Produces<OrderSummary>(fakeBuilder, StatusCodes.Status200OK, "application/json"); EndpointConventionBuilderExtensions.Produces(fakeBuilder, StatusCodes.Status404NotFound); foreach (var convention in fakeBuilder.Conventions) { convention(endpointBuilder); } foreach (var metadata in endpointBuilder.Metadata.OfType<IProducesResponseTypeMetadata>()) { Console.WriteLine( $"Status: {metadata.StatusCode}, " + $"Type: {metadata.Type?.Name ?? "(none)"}, " + $"ContentTypes: {string.Join(", ", metadata.ContentTypes)}"); } } private sealed class FakeEndpointConventionBuilder : IEndpointConventionBuilder { public List<Action<EndpointBuilder>> Conventions { get; } = []; public void Add(Action<EndpointBuilder> convention) => Conventions.Add(convention); } } public sealed record OrderSummary(int Id, string Name);The
Produces<TResponse>andProducesextension members are the same methods used when chaining on aRouteHandlerBuilderinside a Carter module:app.MapGet("/orders/{id}", ...).Produces<OrderSummary>().Produces(404).