Skip to content

Commit 1b061fe

Browse files
authored
Merge pull request #238 from cnblogs/support-async-command-creation
feat: support async query&command creation on minimal api mapping
2 parents 2d39d1f + b307885 commit 1b061fe

File tree

8 files changed

+74
-28
lines changed

8 files changed

+74
-28
lines changed

src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/CqrsRouteMapper.cs

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,29 @@ public static class CqrsRouteMapper
2121

2222
private static readonly string[] GetAndHeadMethods = { "GET", "HEAD" };
2323

24-
private static readonly List<string> PostCommandPrefixes = new() { "Create", "Add", "New" };
24+
private static readonly List<string> PostCommandPrefixes = new()
25+
{
26+
"Create",
27+
"Add",
28+
"New"
29+
};
2530

26-
private static readonly List<string> PutCommandPrefixes = new() { "Update", "Modify", "Replace", "Alter" };
31+
private static readonly List<string> PutCommandPrefixes = new()
32+
{
33+
"Update",
34+
"Modify",
35+
"Replace",
36+
"Alter"
37+
};
2738

28-
private static readonly List<string> DeleteCommandPrefixes = new() { "Delete", "Remove", "Clean", "Clear", "Purge" };
39+
private static readonly List<string> DeleteCommandPrefixes = new()
40+
{
41+
"Delete",
42+
"Remove",
43+
"Clean",
44+
"Clear",
45+
"Purge"
46+
};
2947

3048
/// <summary>
3149
/// Map a query API, using GET method. <typeparamref name="T"/> would been constructed from route and query string.
@@ -96,14 +114,7 @@ public static IEndpointConventionBuilder MapQuery(
96114
string nullRouteParameterPattern = "-",
97115
bool enableHead = false)
98116
{
99-
var isQuery = handler.Method.ReturnType.GetInterfaces().Where(x => x.IsGenericType)
100-
.Any(x => QueryTypes.Contains(x.GetGenericTypeDefinition()));
101-
if (isQuery == false)
102-
{
103-
throw new ArgumentException(
104-
"delegate does not return a query, please make sure it returns object that implement IQuery<> or IListQuery<> or interface that inherit from them");
105-
}
106-
117+
var returnType = EnsureReturnTypeIsQuery(handler);
107118
if (mapNullableRouteParameters is MapNullableRouteParameter.Disable)
108119
{
109120
return MapRoutes(route);
@@ -118,7 +129,7 @@ public static IEndpointConventionBuilder MapQuery(
118129

119130
var parsedRoute = RoutePatternFactory.Parse(route);
120131
var context = new NullabilityInfoContext();
121-
var nullableRouteProperties = handler.Method.ReturnType.GetProperties()
132+
var nullableRouteProperties = returnType.GetProperties()
122133
.Where(
123134
p => p.GetMethod != null
124135
&& p.SetMethod != null
@@ -209,8 +220,7 @@ public static IEndpointConventionBuilder MapCommand(
209220
[StringSyntax("Route")] string route,
210221
Delegate handler)
211222
{
212-
EnsureDelegateReturnTypeIsCommand(handler);
213-
var commandTypeName = handler.Method.ReturnType.Name;
223+
var commandTypeName = EnsureReturnTypeIsCommand(handler).Name;
214224
if (PostCommandPrefixes.Any(x => commandTypeName.StartsWith(x)))
215225
{
216226
return app.MapPostCommand(route, handler);
@@ -255,7 +265,7 @@ public static IEndpointConventionBuilder MapPostCommand(
255265
[StringSyntax("Route")] string route,
256266
Delegate handler)
257267
{
258-
EnsureDelegateReturnTypeIsCommand(handler);
268+
EnsureReturnTypeIsCommand(handler);
259269
return app.MapPost(route, handler).AddEndpointFilter<CommandEndpointHandler>();
260270
}
261271

@@ -285,7 +295,7 @@ public static IEndpointConventionBuilder MapPutCommand(
285295
[StringSyntax("Route")] string route,
286296
Delegate handler)
287297
{
288-
EnsureDelegateReturnTypeIsCommand(handler);
298+
EnsureReturnTypeIsCommand(handler);
289299
return app.MapPut(route, handler).AddEndpointFilter<CommandEndpointHandler>();
290300
}
291301

@@ -315,7 +325,7 @@ public static IEndpointConventionBuilder MapDeleteCommand(
315325
[StringSyntax("Route")] string route,
316326
Delegate handler)
317327
{
318-
EnsureDelegateReturnTypeIsCommand(handler);
328+
EnsureReturnTypeIsCommand(handler);
319329
return app.MapDelete(route, handler).AddEndpointFilter<CommandEndpointHandler>();
320330
}
321331

@@ -385,15 +395,42 @@ public static IEndpointRouteBuilder StopMappingPrefixToDelete(this IEndpointRout
385395
return app;
386396
}
387397

388-
private static void EnsureDelegateReturnTypeIsCommand(Delegate handler)
398+
private static Type EnsureReturnTypeIsCommand(Delegate handler)
389399
{
390-
var isCommand = handler.Method.ReturnType.GetInterfaces().Where(x => x.IsGenericType)
400+
var returnType = handler.Method.ReturnType;
401+
if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
402+
{
403+
returnType = returnType.GenericTypeArguments.First();
404+
}
405+
406+
var isCommand = returnType.GetInterfaces().Where(x => x.IsGenericType)
391407
.Any(x => CommandTypes.Contains(x.GetGenericTypeDefinition()));
392408
if (isCommand == false)
393409
{
394410
throw new ArgumentException(
395411
"handler does not return command, check if delegate returns type that implements ICommand<> or ICommand<,>");
396412
}
413+
414+
return returnType;
415+
}
416+
417+
private static Type EnsureReturnTypeIsQuery(Delegate handler)
418+
{
419+
var returnType = handler.Method.ReturnType;
420+
if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
421+
{
422+
returnType = returnType.GenericTypeArguments.First();
423+
}
424+
425+
var isCommand = returnType.GetInterfaces().Where(x => x.IsGenericType)
426+
.Any(x => QueryTypes.Contains(x.GetGenericTypeDefinition()));
427+
if (isCommand == false)
428+
{
429+
throw new ArgumentException(
430+
"handler does not return query, check if delegate returns type that implements IQuery<>");
431+
}
432+
433+
return returnType;
397434
}
398435

399436
private static List<T[]> GetNotEmptySubsets<T>(ICollection<T> items)

src/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</ItemGroup>
1010
<ItemGroup>
1111
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
12-
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.4" />
12+
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.5" />
1313
</ItemGroup>
1414
<ItemGroup>
1515
<Compile Include="..\Cnblogs.Architecture.Ddd.Cqrs.AspNetCore\CqrsHeaderNames.cs">

src/Cnblogs.Architecture.Ddd.Infrastructure.Dapper.Clickhouse/Cnblogs.Architecture.Ddd.Infrastructure.Dapper.Clickhouse.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</ItemGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="ClickHouse.Client" Version="7.4.1" />
16+
<PackageReference Include="ClickHouse.Client" Version="7.5.0" />
1717
</ItemGroup>
1818

1919
</Project>

src/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.5" />
1313
</ItemGroup>
1414

1515
<ItemGroup>

test/Cnblogs.Architecture.IntegrationTestProject/Cnblogs.Architecture.IntegrationTestProject.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<ItemGroup>
4-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
4+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.1" />
55
</ItemGroup>
66

77
<ItemGroup>

test/Cnblogs.Architecture.IntegrationTestProject/Program.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Cnblogs.Architecture.IntegrationTestProject.Application.Queries;
88
using Cnblogs.Architecture.IntegrationTestProject.Payloads;
99
using Cnblogs.Architecture.TestIntegrationEvents;
10+
using Microsoft.AspNetCore.Mvc;
1011

1112
var builder = WebApplication.CreateBuilder(args);
1213

@@ -36,10 +37,18 @@
3637

3738
var apis = app.NewVersionedApi();
3839
var v1 = apis.MapGroup("/api/v{version:apiVersion}").HasApiVersion(1);
39-
v1.MapQuery<GetStringQuery>("apps/{appId}/strings/{stringId:int}/value", MapNullableRouteParameter.Enable, enableHead: true);
40-
v1.MapQuery<GetStringQuery>("strings/{id:int}");
40+
v1.MapQuery<GetStringQuery>(
41+
"apps/{appId}/strings/{stringId:int}/value",
42+
MapNullableRouteParameter.Enable,
43+
enableHead: true);
44+
v1.MapQuery(
45+
"strings/{stringId:int}",
46+
async (int stringId, [FromQuery] bool found = true)
47+
=> await Task.FromResult(new GetStringQuery(StringId: stringId, Found: found)));
4148
v1.MapQuery<ListStringsQuery>("strings");
42-
v1.MapCommand("strings", (CreatePayload payload) => new CreateCommand(payload.NeedError, payload.Data));
49+
v1.MapCommand(
50+
"strings",
51+
(CreatePayload payload) => Task.FromResult(new CreateCommand(payload.NeedError, payload.Data)));
4352
v1.MapCommand(
4453
"strings/{id:int}",
4554
(int id, UpdatePayload payload) => new UpdateCommand(id, payload.NeedValidationError, payload.NeedExecutionError));

test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<ItemGroup>
33
<PackageReference Include="Cnblogs.Serilog.Extensions" Version="1.1.0" />
4-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.4" />
4+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.5" />
55
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
66
<PackageReference Include="xunit" Version="2.8.0" />
77
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0">

test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<ItemGroup>
4-
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.4" />
4+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.5" />
55
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
66
<PackageReference Include="xunit" Version="2.8.0" />
77
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0">

0 commit comments

Comments
 (0)