DKNet.AspCore.SlimBus 9.5.17

dotnet add package DKNet.AspCore.SlimBus --version 9.5.17
                    
NuGet\Install-Package DKNet.AspCore.SlimBus -Version 9.5.17
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DKNet.AspCore.SlimBus" Version="9.5.17" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DKNet.AspCore.SlimBus" Version="9.5.17" />
                    
Directory.Packages.props
<PackageReference Include="DKNet.AspCore.SlimBus" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DKNet.AspCore.SlimBus --version 9.5.17
                    
#r "nuget: DKNet.AspCore.SlimBus, 9.5.17"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DKNet.AspCore.SlimBus@9.5.17
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DKNet.AspCore.SlimBus&version=9.5.17
                    
Install as a Cake Addin
#tool nuget:?package=DKNet.AspCore.SlimBus&version=9.5.17
                    
Install as a Cake Tool

DKNet.AspCore.SlimBus

NuGet NuGet Downloads .NET License

Minimal API integration helpers for SlimMessageBus + FluentResults, enabling terse, consistent, and well-documented REST endpoints over a CQRS-ish message bus abstraction.

This package focuses on the ASP.NET Core surface (endpoint mapping & HTTP translation). Core CQRS contracts and EF Core behaviors live in DKNet.SlimBus.Extensions.

Key Features

  • โœณ๏ธ One-Liner Endpoint Mapping for commands, queries, paged queries, and void commands
  • ๐Ÿ“ฆ Automatic Response Shaping using FluentResults + ProblemDetails
  • ๐Ÿงพ Standardized Problem Responses via ProducesCommons() contract
  • ๐Ÿ“„ Pagination Wrapper (PagedResult<T>) for IPagedList<T> โ†’ stable JSON shape
  • ๐Ÿ”„ Uniform HTTP Semantics (POST = create vs update; null query response โ†’ 404)
  • ๐Ÿงช Test-Friendly pure extension methods (logic inside bus + results)

Installation

dotnet add package DKNet.AspCore.SlimBus

Also install (if not already):

dotnet add package DKNet.SlimBus.Extensions

When To Use

Scenario Use This Extension
You have SlimMessageBus handlers and want quick HTTP Minimal API exposure โœ…
You use FluentResults for domain outcomes โœ…
You want consistent OpenAPI metadata for common error codes โœ…
You need multi-endpoint CRUD for a resource without hand-writing boilerplate โœ…

Quick Start

var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;

// SlimBus + handlers (from DKNet.SlimBus.Extensions)
services.AddSlimBusForEfCore(b =>
{
    b.WithProviderMemory()
     .AutoDeclareFrom(typeof(CreateProductHandler).Assembly)
     .AddJsonSerializer();
});

var app = builder.Build();
var products = app.MapGroup("/products");

products
    .MapGet<GetProduct, ProductResult>("/{id}")
    .WithName("GetProduct");

products
    .MapGetPage<GetProductsPage, ProductResult>("/")
    .WithName("GetProductsPage");

products
    .MapPost<CreateProduct, ProductResult>("/")
    .WithName("CreateProduct");

products
    .MapPut<UpdateProduct, ProductResult>("/{id}")
    .WithName("UpdateProduct");

products
    .MapDelete<DeleteProduct>("/{id}")
    .WithName("DeleteProduct");

app.Run();

Endpoint Mapping API

All methods extend RouteGroupBuilder and infer OpenAPI metadata.

Method Generic Constraints Behavior
MapGet<TQuery,TResponse> TQuery : Fluents.Queries.IWitResponse<TResponse> Sends query, returns 200 + body or 404 if null
MapGetPage<TQuery,TItem> TQuery : Fluents.Queries.IWitPageResponse<TItem> Wraps IPagedList<TItem> in PagedResult<TItem>
MapPost<TCommand,TResponse> TCommand : Fluents.Requests.IWitResponse<TResponse> Sends command, 201 Created (location "/") on success
MapPost<TCommand> TCommand : Fluents.Requests.INoResponse 200 OK / Problem
MapPut<TCommand,TResponse> TCommand : Fluents.Requests.IWitResponse<TResponse> 200 OK with value or Problem
MapPut<TCommand> TCommand : Fluents.Requests.INoResponse 200 OK / Problem
MapPatch<TCommand,TResponse> same as Put Partial update semantics
MapPatch<TCommand> same as Put Partial update no response
MapDelete<TCommand,TResponse> TCommand : Fluents.Requests.IWitResponse<TResponse> 200 OK with value / Problem
MapDelete<TCommand> TCommand : Fluents.Requests.INoResponse 200 OK / Problem

All return a RouteHandlerBuilder enabling further customization (e.g., .RequireAuthorization()).

Common Response Metadata

Call .ProducesCommons() automatically (already applied internally by the mapping helpers) to register standardized error codes:

  • 400 (ProblemDetails) validation / domain errors
  • 401 / 403 auth/authz
  • 404 not found (for null query result)
  • 409 conflict
  • 429 rate limiting
  • 500 server error

FluentResults โ†’ HTTP Translation

ResultResponseExtensions define:

public static IResult Response<T>(this IResult<T> result, bool isCreated = false);
public static IResult Response(this IResultBase result, bool isCreated = false);

Rules:

  • Failure โ†’ ProblemDetails (400 by default)
  • Success + isCreated โ†’ 201 Created with payload
  • Success + null value โ†’ 200 Ok (no body)
  • Success + value โ†’ JSON body

ProblemDetails Extensions

result.ToProblemDetails();              // From IResultBase
modelState.ToProblemDetails();          // From ModelStateDictionary

Aggregates distinct error messages into extensions.errors.

Example output:

{
  "status": 400,
  "type": "BadRequest",
  "title": "Error",
  "detail": "Name is required",
  "errors": ["Name is required", "Price must be positive"]
}

Pagination Wrapper

PagedResult<T> converts an IPagedList<T> into a transport-friendly DTO:

{
  "pageNumber": 1,
  "pageSize": 20,
  "pageCount": 7,
  "totalItemCount": 123,
  "items": [ { /* ... */ } ]
}

Returned automatically by MapGetPage.

Defining Requests & Handlers (from DKNet.SlimBus.Extensions)

public record GetProduct : Fluents.Queries.IWitResponse<ProductDto>
{
    public Guid Id { get; init; }
}

public class GetProductHandler : Fluents.Queries.IHandler<GetProduct, ProductDto>
{
    private readonly AppDbContext _db; private readonly IMapper _m;
    public GetProductHandler(AppDbContext db, IMapper m) { _db = db; _m = m; }

    public async Task<ProductDto?> Handle(GetProduct q, CancellationToken ct) =>
        await _db.Products.Where(p => p.Id == q.Id)
            .Select(p => _m.Map<ProductDto>(p))
            .FirstOrDefaultAsync(ct);
}

Binding With [AsParameters]

For GET endpoints the query object is bound via [AsParameters] automatically when using the helpers, enabling clean record definitions:

public record GetProductsPage(int PageIndex = 0, int PageSize = 20) : Fluents.Queries.IWitPageResponse<ProductDto>;

Composing Policies / Filters

products
  .MapPost<CreateProduct, ProductResult>("/")
  .RequireAuthorization("ProductsWrite")
  .AddEndpointFilter(new LoggingFilter());

Error Scenarios & Status Codes

Situation Result Pattern HTTP Body
Domain validation fails Result.Fail("msg") 400 ProblemDetails
Query returns null null 404 ProblemDetails (none)
Command succeeds (create) Result.Ok(value) + created flag 201 JSON
Command succeeds (no value) Result.Ok() 200 (empty)
Unhandled exception n/a 500 (standard)

Extending

Add your own composite methods:

public static class ProductEndpointGroup
{
    public static RouteGroupBuilder MapProductEndpoints(this IEndpointRouteBuilder app)
    {
        var g = app.MapGroup("/products");
        g.MapGet<GetProduct, ProductDto>("/{id}");
        g.MapPost<CreateProduct, ProductDto>("/");
        return g;
    }
}

Testing Patterns

Because the endpoint methods only orchestrate bus + translation, prefer unit testing handlers and a minimal integration test asserting mapping correctness:

// Arrange: host with in-memory bus stub
// Act: HTTP call
// Assert: status + payload shape

Versioning & Compatibility

Package Purpose
DKNet.AspCore.SlimBus HTTP layer & endpoint helpers
DKNet.SlimBus.Extensions Core CQRS abstractions, EF behaviors

Targets .NET 9+. Uses ASP.NET Core Minimal APIs.

Roadmap / Ideas

  • Optional Location URI delegate for Created responses
  • Customizable default problem title / type mapping
  • OpenTelemetry activity tagging
  • Inline endpoint filter helpers (validation, caching)

Contributing

PRs welcome. Keep helpers minimal and side-effect free. Larger concerns (transactions, persistence, events) belong in the core extensions library.

License

MIT ยฉ DKNet

See Also

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
9.5.17 0 10/17/2025
9.5.16 0 10/17/2025
9.5.15 43 10/15/2025
9.5.14 75 10/14/2025
9.5.13 74 10/14/2025
9.5.12 69 10/14/2025
9.5.11 67 10/14/2025
9.5.10 62 10/14/2025
9.5.9 78 10/13/2025
9.5.8 66 10/11/2025
9.5.7 96 10/10/2025
9.5.6 99 10/10/2025
9.5.5 104 10/10/2025
9.5.4 110 10/10/2025
9.5.3 142 10/8/2025
9.5.2 144 10/8/2025
9.5.1 157 10/7/2025
9.0.42 158 10/6/2025
9.0.41 162 10/2/2025
9.0.40 159 10/2/2025