Xpandables.AspNetCore.Net
10.0.2
dotnet add package Xpandables.AspNetCore.Net --version 10.0.2
NuGet\Install-Package Xpandables.AspNetCore.Net -Version 10.0.2
<PackageReference Include="Xpandables.AspNetCore.Net" Version="10.0.2" />
<PackageVersion Include="Xpandables.AspNetCore.Net" Version="10.0.2" />
<PackageReference Include="Xpandables.AspNetCore.Net" />
paket add Xpandables.AspNetCore.Net --version 10.0.2
#r "nuget: Xpandables.AspNetCore.Net, 10.0.2"
#:package Xpandables.AspNetCore.Net@10.0.2
#addin nuget:?package=Xpandables.AspNetCore.Net&version=10.0.2
#tool nuget:?package=Xpandables.AspNetCore.Net&version=10.0.2
🌐 AspNetCore.Net
Minimal API routing, metadata, and JSON helpers for organized ASP.NET Core applications.
📋 Overview
AspNetCore.Net keeps minimal APIs tidy by giving you a small set of primitives: modular endpoint modules, a route builder that applies cross-cutting conventions, consistent OpenAPI metadata helpers, and easy access to the configured JsonSerializerOptions. Everything is designed for .NET 10, trimming, and AOT-friendly builds.
✨ Key Features
- 🛣️ Modular endpoint modules — Implement sealed
IMinimalEndpointRouteclasses and register them withAddXMinimalEndpointRoutes(...)for automatic discovery. - ⚙️ Cross-cutting configuration —
AddXMinimalSupportexposesMinimalSupportOptionsso you can attach conventions (authorization, OpenAPI, CORS, etc.) to endpoints, optionally filtered by a predicate. - 🧭 Routing helpers —
MinimalRouteBuilderwrapsIEndpointRouteBuilderwithMapGet/MapPost/MapPut/MapDelete/MapPatch/MapMethods/MapGroupthat automatically apply your configured filters. - 🎯 Metadata helpers —
Accepts<T>()andProducesXXX()helpers standardize status codes and content types for consistent OpenAPI docs. - 📝 JSON helpers —
AddXJsonSerializerOptions()registers the configuredJsonSerializerOptionsas a singleton;HttpContexthelpers surface serializer options, content type, and encoding per request.
📦 Installation
dotnet add package AspNetCore.Net
Or via NuGet Package Manager:
Install-Package AspNetCore.Net
🚀 Quick Start
Service Registration
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Configure how endpoints are decorated
builder.Services.AddXMinimalSupport(options =>
{
// Apply conventions only to /api endpoints
options.EndpointPredicate = endpoint =>
endpoint.RoutePattern.RawText?.StartsWith("/api") ?? false;
// Attach cross-cutting conventions
options.ConfigureEndpoint = endpoint =>
{
endpoint.RequireAuthorization();
endpoint.WithOpenApi();
};
});
// Auto-discover sealed IMinimalEndpointRoute modules in the entry assembly
builder.Services.AddXMinimalEndpointRoutes(typeof(Program).Assembly);
// Expose the configured JsonSerializerOptions for DI consumers
builder.Services.AddXJsonSerializerOptions();
var app = builder.Build();
app.UseHttpsRedirection();
// Wire up all discovered minimal endpoint routes
app.UseXMinimalEndpointRoutes();
app.Run();
🛣️ Modular Endpoint Routing
Define Endpoint Routes
Create sealed modules that implement IMinimalEndpointRoute. Each module receives a MinimalRouteBuilder, so every mapped endpoint automatically inherits your configured filters and metadata helpers.
using Microsoft.AspNetCore.Routing;
public sealed class OrdersEndpoints : IMinimalEndpointRoute
{
public void AddRoutes(MinimalRouteBuilder app)
{
var group = app.MapGroup("/api/orders").WithTags("Orders");
group.MapGet("/", GetOrders)
.Produces200OK<IEnumerable<OrderSummary>>()
.Produces500InternalServerError();
group.MapGet("/{id:guid}", GetOrderById)
.Produces200OK<OrderDetails>()
.Produces404NotFound();
group.MapPost("/", CreateOrder)
.Accepts<CreateOrderRequest>()
.Produces201Created<OrderDetails>()
.Produces400BadRequest();
}
private static async Task<IResult> GetOrders(IOrdersService service, CancellationToken ct)
{
var orders = await service.ListAsync(ct);
return Results.Ok(orders);
}
private static async Task<IResult> GetOrderById(Guid id, IOrdersService service, CancellationToken ct)
{
var order = await service.GetAsync(id, ct);
return order is null ? Results.NotFound() : Results.Ok(order);
}
private static async Task<IResult> CreateOrder(
CreateOrderRequest request,
IOrdersService service,
CancellationToken ct)
{
var created = await service.CreateAsync(request, ct);
return Results.Created($"/api/orders/{created.Id}", created);
}
}
Register and Use
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddXMinimalSupport();
builder.Services.AddXMinimalEndpointRoutes(typeof(Program).Assembly);
var app = builder.Build();
app.UseXMinimalEndpointRoutes();
app.Run();
🎯 Route Metadata Extensions
Fluent helpers add OpenAPI-friendly metadata without repeating status codes or content types.
public void AddRoutes(MinimalRouteBuilder app)
{
app.MapGet("/api/users", GetUsers)
.Produces200OK<IEnumerable<User>>()
.Produces500InternalServerError();
app.MapPost("/api/users", CreateUser)
.Accepts<CreateUserRequest>()
.Produces201Created<User>()
.Produces400BadRequest();
app.MapMethods("/api/users/{id}/activate", ["PATCH"], ActivateUser)
.Produces200OK()
.Produces405MethodNotAllowed();
}
Available Metadata Extensions
| Extension | Status Code | Content Type |
|---|---|---|
Produces200OK() |
200 | application/json |
Produces200OK<T>() |
200 | application/json |
Produces201Created<T>() |
201 | application/json |
Produces400BadRequest() |
400 | application/problem+json |
Produces401Unauthorized() |
401 | application/problem+json |
Produces404NotFound() |
404 | application/problem+json |
Produces405MethodNotAllowed() |
405 | application/problem+json |
Produces409Conflict() |
409 | application/problem+json |
Produces500InternalServerError() |
500 | application/problem+json |
Accepts<T>() |
— | application/json |
⚙️ Minimal Support Options
Control which endpoints receive cross-cutting conventions and how they are configured.
builder.Services.AddXMinimalSupport(options =>
{
// Only apply conventions to API endpoints
options.EndpointPredicate = endpoint => endpoint.RoutePattern.RawText?.StartsWith("/api") ?? false;
// Add conventions to matching endpoints
options.ConfigureEndpoint = builder =>
{
builder.RequireAuthorization();
builder.WithOpenApi();
};
});
Options
| Property | Type | Description |
|---|---|---|
EndpointPredicate |
Func<RouteEndpoint, bool>? |
Filter which endpoints receive configuration. |
ConfigureEndpoint |
Action<IEndpointConventionBuilder>? |
Apply conventions/metadata to matching endpoints. |
📝 JSON Serializer Options
Expose your app's configured JsonSerializerOptions to any service via DI.
// Program.cs
builder.Services.AddXJsonSerializerOptions();
// Service using the shared options
public sealed class ExportService(JsonSerializerOptions jsonOptions)
{
public string ToJson<T>(T value) => JsonSerializer.Serialize(value, jsonOptions);
}
HttpContext helpers
Retrieve request-scoped serialization settings and content negotiation details.
app.MapGet("/api/profile", (HttpContext ctx) =>
{
var options = ctx.GetJsonSerializerOptionsOrDefault();
var contentType = ctx.GetContentType("application/json");
var encoding = ctx.GetEncoding();
return Results.Ok(new
{
SerializerIndented = options.WriteIndented,
ContentType = contentType,
Encoding = encoding.WebName
});
});
Helpers include GetJsonSerializerOptions(), GetMvcJsonSerializerOptions(), GetJsonSerializerOptionsOrDefault(), GetMvcJsonSerializerOptionsOrDefault(), GetContentType(), GetContentType(string defaultContentType), and GetEncoding().
🏗️ Complete Example
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Apply OpenAPI + auth only to API endpoints
builder.Services.AddXMinimalSupport(options =>
{
options.EndpointPredicate = endpoint => endpoint.RoutePattern.RawText?.StartsWith("/api") ?? false;
options.ConfigureEndpoint = b =>
{
b.RequireAuthorization();
b.WithOpenApi();
};
});
builder.Services.AddXMinimalEndpointRoutes(typeof(Program).Assembly);
builder.Services.AddXJsonSerializerOptions();
var app = builder.Build();
app.UseHttpsRedirection();
app.MapGet("/health", () => Results.Ok(new { status = "ok" }))
.Produces200OK()
.WithTags("Health");
app.UseXMinimalEndpointRoutes();
app.Run();
// Example endpoint module
public sealed class CustomersEndpoints : IMinimalEndpointRoute
{
public void AddRoutes(MinimalRouteBuilder app)
{
var group = app.MapGroup("/api/customers").WithTags("Customers");
group.MapGet("/", GetCustomers)
.Produces200OK<IEnumerable<CustomerSummary>>();
group.MapGet("/{id:guid}", GetCustomer)
.Produces200OK<CustomerDetails>()
.Produces404NotFound();
}
private static IResult GetCustomers(ICustomerStore store) =>
Results.Ok(store.List());
private static IResult GetCustomer(Guid id, ICustomerStore store) =>
store.TryGet(id, out var customer)
? Results.Ok(customer)
: Results.NotFound();
}
✅ Best Practices
- Use sealed
IMinimalEndpointRoutemodules to keep endpoints cohesive and discoverable. - Apply
AddXMinimalSupportto centralize conventions (auth, OpenAPI, CORS) instead of repeating per endpoint. - Use
Accepts<T>()andProducesXXX()helpers to keep OpenAPI metadata consistent. - Call
AddXJsonSerializerOptions()once so services share the same serializer settings configured by ASP.NET Core. - Prefer
MapGroupto scope tags and prefixes for related endpoints.
📚 Related Packages
| Package | Description |
|---|---|
| AspNetCore.Results | Result pattern integration for HTTP responses |
| AspNetCore.AsyncPaged | Async paged enumerable HTTP streaming |
| System.Composition | MEF composition utilities |
📄 License
Apache License 2.0 - Copyright © Kamersoft 2025
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Xpandables.AspNetCore.Net:
| Package | Downloads |
|---|---|
|
Xpandables.AspNetCore.Results
Package Description |
|
|
Xpandables.AspNetCore.AsyncPaged
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.