CommandQuery.AspNetCore
4.0.0
dotnet add package CommandQuery.AspNetCore --version 4.0.0
NuGet\Install-Package CommandQuery.AspNetCore -Version 4.0.0
<PackageReference Include="CommandQuery.AspNetCore" Version="4.0.0" />
paket add CommandQuery.AspNetCore --version 4.0.0
#r "nuget: CommandQuery.AspNetCore, 4.0.0"
// Install CommandQuery.AspNetCore as a Cake Addin #addin nuget:?package=CommandQuery.AspNetCore&version=4.0.0 // Install CommandQuery.AspNetCore as a Cake Tool #tool nuget:?package=CommandQuery.AspNetCore&version=4.0.0
CommandQuery.AspNetCore 🌐
Command Query Separation for ASP.NET Core
- Provides generic actions for handling the execution of commands and queries
- Enables APIs based on HTTP
POST
andGET
Get Started
- Create a new ASP.NET Core project
- Install the
CommandQuery.AspNetCore
package from NuGetPM>
Install-Package CommandQuery.AspNetCore
- Create commands and command handlers
- Implement
ICommand
andICommandHandler<in TCommand>
- Or
ICommand<TResult>
andICommandHandler<in TCommand, TResult>
- Implement
- Create queries and query handlers
- Implement
IQuery<TResult>
andIQueryHandler<in TQuery, TResult>
- Implement
- Configure services in
Startup.cs
Choose:
- .NET 8.0 (Long Term Support)
- Use controllers
Configuration
Configuration in Program.cs
:
using CommandQuery;
using CommandQuery.AspNetCore;
using CommandQuery.Sample.Contracts.Commands;
using CommandQuery.Sample.Contracts.Queries;
using CommandQuery.Sample.Handlers;
using CommandQuery.Sample.Handlers.Commands;
using CommandQuery.Sample.Handlers.Queries;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add commands and queries
builder.Services.AddCommandControllers(typeof(FooCommandHandler).Assembly, typeof(FooCommand).Assembly);
builder.Services.AddQueryControllers(typeof(BarQueryHandler).Assembly, typeof(BarQuery).Assembly);
// Add handler dependencies
builder.Services.AddTransient<IDateTimeProxy, DateTimeProxy>();
builder.Services.AddTransient<ICultureService, CultureService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
// Validation
app.Services.GetService<ICommandProcessor>()!.AssertConfigurationIsValid();
app.Services.GetService<IQueryProcessor>()!.AssertConfigurationIsValid();
app.Run();
The extension methods AddCommandControllers
and AddQueryControllers
will add controllers and all command/query handlers in the given assemblies to the IoC container.
You can pass in a params
array of Assembly
arguments if your handlers are located in different projects.
If you only have one project you can use typeof(Startup).Assembly
as a single argument.
Commands
The action method from the generated controller will handle commands:
/// <summary>
/// Handle a command.
/// </summary>
/// <param name="command">The command.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>The result for status code <c>200</c>, or an error for status code <c>400</c> and <c>500</c>.</returns>
[HttpPost]
public async Task<IActionResult> HandleAsync(TCommand command, CancellationToken cancellationToken)
- The action is requested via HTTP
POST
with the Content-Typeapplication/json
in the header - The name of the command is the slug of the URL
- The command itself is provided as JSON in the body
- If the command succeeds; the response is empty with the HTTP status code
200
- If the command fails; the response is an error message with the HTTP status code
400
or500
Commands with result:
/// <summary>
/// Handle a command.
/// </summary>
/// <param name="command">The command.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>The result for status code <c>200</c>, or an error for status code <c>400</c> and <c>500</c>.</returns>
[HttpPost]
public async Task<IActionResult> HandleAsync(TCommand command, CancellationToken cancellationToken)
- If the command succeeds; the response is the result as JSON with the HTTP status code
200
. - If the command fails; the response is an error message with the HTTP status code
400
or500
.
Queries
The action methods from the generated controller will handle queries:
/// <summary>
/// Handle a query.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>The result + 200, 400 or 500.</returns>
[HttpPost]
public async Task<IActionResult> HandlePostAsync(TQuery query, CancellationToken cancellationToken)
/// <summary>
/// Handle a query.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>The result + 200, 400 or 500.</returns>
[HttpGet]
public async Task<IActionResult> HandleGetAsync([FromQuery] TQuery query, CancellationToken cancellationToken)
- The action is requested via:
- HTTP
POST
with the Content-Typeapplication/json
in the header and the query itself as JSON in the body - HTTP
GET
and the query itself as query string parameters in the URL
- HTTP
- The name of the query is the slug of the URL.
- If the query succeeds; the response is the result as JSON with the HTTP status code
200
. - If the query fails; the response is an error message with the HTTP status code
400
or500
.
Testing
You can integration test your controllers and command/query handlers with the Microsoft.AspNetCore.Mvc.Testing
package.
using System.Net;
using System.Net.Http.Json;
using CommandQuery.Sample.Contracts.Commands;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using NUnit.Framework;
namespace CommandQuery.Sample.AspNetCore.Tests
{
public class CommandControllerTests
{
[SetUp]
public void SetUp()
{
Factory = new WebApplicationFactory<Program>();
Client = Factory.CreateClient();
}
[TearDown]
public void TearDown()
{
Client.Dispose();
Factory.Dispose();
}
[Test]
public async Task should_handle_command()
{
var response = await Client.PostAsJsonAsync("/api/command/FooCommand", new FooCommand { Value = "Foo" });
response.StatusCode.Should().Be(HttpStatusCode.OK);
}
[Test]
public async Task should_handle_errors()
{
var response = await Client.PostAsJsonAsync("/api/command/FooCommand", new FooCommand { Value = "" });
await response.ShouldBeErrorAsync("Value cannot be null or empty");
}
WebApplicationFactory<Program> Factory = null!;
HttpClient Client = null!;
}
}
Samples
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. |
-
net8.0
- CommandQuery (>= 4.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on CommandQuery.AspNetCore:
Repository | Stars |
---|---|
hlaueriksson/CommandQuery
Command Query Separation for 🌐ASP.NET Core ⚡AWS Lambda ⚡Azure Functions ⚡Google Cloud Functions
|
Version | Downloads | Last updated |
---|---|---|
4.0.0 | 130 | 7/13/2024 |
3.0.0 | 519 | 1/9/2023 |
2.0.0 | 748 | 7/29/2021 |
1.0.0 | 2,185 | 2/2/2020 |
0.9.0 | 1,511 | 11/20/2019 |
0.8.0 | 4,161 | 2/16/2019 |
0.7.0 | 1,017 | 9/22/2018 |
0.6.0 | 957 | 9/15/2018 |
0.5.0 | 1,084 | 7/6/2018 |
0.4.0 | 1,027 | 5/16/2018 |
0.3.2 | 1,133 | 5/1/2018 |
0.3.1 | 1,125 | 1/6/2018 |
0.3.0 | 1,120 | 1/3/2018 |
0.2.0 | 1,073 | 4/25/2017 |
- Change TargetFramework to net8.0