NetEvolve.Pulse.AspNetCore
0.17.3
Prefix Reserved
dotnet add package NetEvolve.Pulse.AspNetCore --version 0.17.3
NuGet\Install-Package NetEvolve.Pulse.AspNetCore -Version 0.17.3
<PackageReference Include="NetEvolve.Pulse.AspNetCore" Version="0.17.3" />
<PackageVersion Include="NetEvolve.Pulse.AspNetCore" Version="0.17.3" />
<PackageReference Include="NetEvolve.Pulse.AspNetCore" />
paket add NetEvolve.Pulse.AspNetCore --version 0.17.3
#r "nuget: NetEvolve.Pulse.AspNetCore, 0.17.3"
#:package NetEvolve.Pulse.AspNetCore@0.17.3
#addin nuget:?package=NetEvolve.Pulse.AspNetCore&version=0.17.3
#tool nuget:?package=NetEvolve.Pulse.AspNetCore&version=0.17.3
NetEvolve.Pulse.AspNetCore
NetEvolve.Pulse.AspNetCore provides IEndpointRouteBuilder extension methods that map Pulse mediator commands and queries directly to ASP.NET Core Minimal API HTTP endpoints. Eliminate the boilerplate of endpoint lambdas that only forward to IMediator.
Features
MapCommand<TCommand, TResponse>: Maps a command to an HTTP endpoint returning200 OKwith the response. Defaults toPOSTwhen no method is specified; accepts anyCommandHttpMethodvalue.MapCommand<TCommand>: Maps a void command to an HTTP endpoint returning204 No Content. Defaults toPOSTwhen no method is specified; accepts anyCommandHttpMethodvalue.MapQuery<TQuery, TResponse>: Maps a query to aGETendpoint returning200 OKwith the result.CommandHttpMethodenum: Strongly-typed HTTP method selection —Post,Put,Patch,Delete.GETis excluded by design since commands are state-changing operations.- CancellationToken propagation: Automatically propagates the HTTP request cancellation token.
- OpenAPI compatible: Returns typed results (
TypedResults) soWithOpenApi()produces correct response schemas. - DI-based:
IMediatoris resolved from the request scope at runtime — no compile-time dependency onNetEvolve.Pulse.
Installation
NuGet Package Manager
Install-Package NetEvolve.Pulse.AspNetCore
.NET CLI
dotnet add package NetEvolve.Pulse.AspNetCore
PackageReference
<PackageReference Include="NetEvolve.Pulse.AspNetCore" Version="x.x.x" />
Quick Start
using NetEvolve.Pulse;
var builder = WebApplication.CreateBuilder(args);
// Register Pulse and handlers
builder.Services.AddPulse();
builder.Services.AddScoped<ICommandHandler<CreateOrderCommand, OrderResult>, CreateOrderHandler>();
builder.Services.AddScoped<ICommandHandler<UpdateOrderCommand, OrderResult>, UpdateOrderHandler>();
builder.Services.AddScoped<ICommandHandler<DeleteOrderCommand, Void>, DeleteOrderHandler>();
builder.Services.AddScoped<IQueryHandler<GetOrderQuery, OrderDto>, GetOrderHandler>();
var app = builder.Build();
// Map commands and queries — no boilerplate lambdas needed
app.MapCommand<CreateOrderCommand, OrderResult>("/orders"); // POST /orders
app.MapCommand<UpdateOrderCommand, OrderResult>("/orders/{id}", CommandHttpMethod.Put); // PUT /orders/{id}
app.MapCommand<DeleteOrderCommand>("/orders/{id}", CommandHttpMethod.Delete); // DELETE /orders/{id}
app.MapQuery<GetOrderQuery, OrderDto>("/orders/{id}"); // GET /orders/{id}
app.Run();
Without this package you would write:
app.MapPost("/orders", async (CreateOrderCommand cmd, IMediator mediator, CancellationToken ct) =>
Results.Ok(await mediator.SendAsync<CreateOrderCommand, OrderResult>(cmd, ct)));
app.MapPut("/orders/{id}", async (UpdateOrderCommand cmd, IMediator mediator, CancellationToken ct) =>
Results.Ok(await mediator.SendAsync<UpdateOrderCommand, OrderResult>(cmd, ct)));
app.MapDelete("/orders/{id}", async ([FromBody] DeleteOrderCommand cmd, IMediator mediator, CancellationToken ct) =>
{
await mediator.SendAsync<DeleteOrderCommand>(cmd, ct);
return Results.NoContent();
});
app.MapGet("/orders/{id}", async ([AsParameters] GetOrderQuery query, IMediator mediator, CancellationToken ct) =>
Results.Ok(await mediator.QueryAsync<GetOrderQuery, OrderDto>(query, ct)));
Usage
Commands with a Response
MapCommand<TCommand, TResponse> binds the request body to TCommand, sends it via IMediator.SendAsync, and returns 200 OK with the result. The default HTTP method is POST; use the CommandHttpMethod parameter to choose a different method:
// POST /orders (default)
app.MapCommand<CreateOrderCommand, OrderResult>("/orders");
// PUT /orders/{id}
app.MapCommand<UpdateOrderCommand, OrderResult>("/orders/{id}", CommandHttpMethod.Put);
// PATCH /orders/{id}
app.MapCommand<PatchOrderCommand, OrderResult>("/orders/{id}", CommandHttpMethod.Patch);
public record CreateOrderCommand(string Sku, int Quantity) : ICommand<OrderResult>;
public record UpdateOrderCommand(Guid Id, string Sku, int Quantity) : ICommand<OrderResult>;
public record OrderResult(Guid OrderId, string Status);
Void Commands
MapCommand<TCommand> binds the request body to TCommand, sends it via IMediator.SendAsync, and returns 204 No Content. The default HTTP method is POST:
// POST /orders/cancel (default)
app.MapCommand<CancelOrderCommand>("/orders/cancel");
// DELETE /orders/{id}
app.MapCommand<DeleteOrderCommand>("/orders/{id}", CommandHttpMethod.Delete);
public record CancelOrderCommand(Guid Id) : ICommand;
public record DeleteOrderCommand(Guid Id) : ICommand;
Queries
MapQuery<TQuery, TResponse> registers a GET endpoint that binds route parameters and query string to TQuery using [AsParameters], executes the query via IMediator.QueryAsync, and returns 200 OK with the result:
app.MapQuery<GetOrderQuery, OrderDto>("/orders/{id}");
public record GetOrderQuery(Guid Id) : IQuery<OrderDto>;
public record OrderDto(Guid Id, string Sku, string Status);
CommandHttpMethod Enum
The CommandHttpMethod enum controls the HTTP method registered for command endpoints. GET is intentionally excluded because commands are state-changing operations — use MapQuery for read-only operations instead:
| Value | HTTP Method | Typical use |
|---|---|---|
Post (default) |
POST |
Create a new resource |
Put |
PUT |
Replace an existing resource |
Patch |
PATCH |
Partially update a resource |
Delete |
DELETE |
Remove a resource |
Passing an undefined enum value throws ArgumentOutOfRangeException.
Chaining Endpoint Configuration
All methods return RouteHandlerBuilder, so you can chain Minimal API metadata:
app.MapCommand<CreateOrderCommand, OrderResult>("/orders")
.WithName("CreateOrder")
.WithTags("Orders")
.WithOpenApi()
.RequireAuthorization();
app.MapCommand<DeleteOrderCommand>("/orders/{id}", CommandHttpMethod.Delete)
.WithName("DeleteOrder")
.WithTags("Orders")
.WithOpenApi()
.RequireAuthorization();
app.MapQuery<GetOrderQuery, OrderDto>("/orders/{id}")
.WithName("GetOrder")
.WithTags("Orders")
.WithOpenApi()
.RequireAuthorization("ReadOrders");
Grouping Endpoints
Combine with MapGroup for shared prefixes and metadata:
var orders = app.MapGroup("/orders")
.WithTags("Orders")
.RequireAuthorization();
orders.MapCommand<CreateOrderCommand, OrderResult>("/");
orders.MapCommand<UpdateOrderCommand, OrderResult>("/{id}", CommandHttpMethod.Put);
orders.MapCommand<DeleteOrderCommand>("/{id}", CommandHttpMethod.Delete);
orders.MapQuery<GetOrderQuery, OrderDto>("/{id}");
Requirements
- .NET 8.0, .NET 9.0, or .NET 10.0
- ASP.NET Core (included in the SDK)
NetEvolve.Pulse(or anyIMediatorimplementation) registered in the DI container
Related Packages
- NetEvolve.Pulse - Core CQRS mediator
- NetEvolve.Pulse.Extensibility - Extensibility contracts
- NetEvolve.Pulse.Polly - Polly v8 resilience policies integration
- NetEvolve.Pulse.EntityFramework - Entity Framework Core outbox persistence
- NetEvolve.Pulse.SqlServer - SQL Server ADO.NET outbox persistence
Contributing
Contributions are welcome! Please read the Contributing Guidelines before submitting a pull request.
Support
- Issues: Report bugs or request features on GitHub Issues
- Documentation: Read the full documentation at https://github.com/dailydevops/pulse
License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ by the NetEvolve Team
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. 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 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
- NetEvolve.Pulse.Extensibility (>= 0.17.3)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- NetEvolve.Pulse.Extensibility (>= 0.17.3)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- NetEvolve.Pulse.Extensibility (>= 0.17.3)
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 |
|---|---|---|
| 0.17.3 | 200 | 3/28/2026 |