From a15cfb0d74444a025a2f3fd64441484eaa4043f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 02:51:00 +0000 Subject: [PATCH 1/9] chore(deps): bump xunit from 2.8.0 to 2.8.1 Bumps [xunit](https://github.com/xunit/xunit) from 2.8.0 to 2.8.1. - [Commits](https://github.com/xunit/xunit/compare/2.8.0...2.8.1) --- updated-dependencies: - dependency-name: xunit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Cnblogs.Architecture.IntegrationTests.csproj | 2 +- .../Cnblogs.Architecture.UnitTests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj index 2b6ad3f..06a3478 100644 --- a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj +++ b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj @@ -3,7 +3,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj index 6db550f..559f92e 100644 --- a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj +++ b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj @@ -3,7 +3,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From efb294c6d85ca740a05380367fea4093465b8610 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 02:51:29 +0000 Subject: [PATCH 2/9] chore(deps): bump Swashbuckle.AspNetCore from 6.6.1 to 6.6.2 Bumps [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) from 6.6.1 to 6.6.2. - [Release notes](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/releases) - [Commits](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/compare/v6.6.1...v6.6.2) --- updated-dependencies: - dependency-name: Swashbuckle.AspNetCore dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Cnblogs.Architecture.IntegrationTestProject.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Cnblogs.Architecture.IntegrationTestProject/Cnblogs.Architecture.IntegrationTestProject.csproj b/test/Cnblogs.Architecture.IntegrationTestProject/Cnblogs.Architecture.IntegrationTestProject.csproj index 799840f..df9e4ca 100644 --- a/test/Cnblogs.Architecture.IntegrationTestProject/Cnblogs.Architecture.IntegrationTestProject.csproj +++ b/test/Cnblogs.Architecture.IntegrationTestProject/Cnblogs.Architecture.IntegrationTestProject.csproj @@ -1,7 +1,7 @@  - + From 49231d09e350fc23452bfebae4ce1add8824ba93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 03:22:02 +0000 Subject: [PATCH 3/9] chore(deps): bump xunit.runner.visualstudio from 2.8.0 to 2.8.1 Bumps [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit) from 2.8.0 to 2.8.1. - [Release notes](https://github.com/xunit/visualstudio.xunit/releases) - [Commits](https://github.com/xunit/visualstudio.xunit/compare/2.8.0...2.8.1) --- updated-dependencies: - dependency-name: xunit.runner.visualstudio dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Cnblogs.Architecture.IntegrationTests.csproj | 2 +- .../Cnblogs.Architecture.UnitTests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj index 06a3478..cf79667 100644 --- a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj +++ b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj @@ -4,7 +4,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj index 559f92e..7418cab 100644 --- a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj +++ b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj @@ -4,7 +4,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 061677a2eb7d8f16005fff3e5c9d7c922a03188c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 03:22:03 +0000 Subject: [PATCH 4/9] chore(deps): bump Microsoft.NET.Test.Sdk from 17.9.0 to 17.10.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.9.0 to 17.10.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/compare/v17.9.0...v17.10.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../Cnblogs.Architecture.IntegrationTests.csproj | 2 +- .../Cnblogs.Architecture.UnitTests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj index 06a3478..bf3280b 100644 --- a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj +++ b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj @@ -2,7 +2,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj index 559f92e..a395765 100644 --- a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj +++ b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj @@ -2,7 +2,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive From be9416a5a008f5a29f073c1ccf61a6cd55192829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E6=98=9F=E7=B9=81?= Date: Fri, 31 May 2024 11:14:57 +0800 Subject: [PATCH 5/9] chore: upgrade packages --- .../Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent.csproj | 2 +- ...blogs.Architecture.Ddd.Infrastructure.EntityFramework.csproj | 2 +- .../Cnblogs.Architecture.IntegrationTests.csproj | 2 +- .../Cnblogs.Architecture.UnitTests.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent.csproj b/src/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent.csproj index 53f1d17..968c4bc 100644 --- a/src/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent.csproj +++ b/src/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent/Cnblogs.Architecture.Ddd.Cqrs.ServiceAgent.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework.csproj b/src/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework.csproj index 47f95bf..b02f255 100644 --- a/src/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework.csproj +++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework/Cnblogs.Architecture.Ddd.Infrastructure.EntityFramework.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj index d702abd..8113384 100644 --- a/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj +++ b/test/Cnblogs.Architecture.IntegrationTests/Cnblogs.Architecture.IntegrationTests.csproj @@ -1,7 +1,7 @@ - + diff --git a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj index 5bd24a3..2f923c1 100644 --- a/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj +++ b/test/Cnblogs.Architecture.UnitTests/Cnblogs.Architecture.UnitTests.csproj @@ -1,7 +1,7 @@ - + From fdab5085a237efc315fb13a6fb394887eae3de11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 02:40:43 +0000 Subject: [PATCH 6/9] chore(deps): bump Microsoft.Data.SqlClient from 5.2.0 to 5.2.1 Bumps [Microsoft.Data.SqlClient](https://github.com/dotnet/sqlclient) from 5.2.0 to 5.2.1. - [Release notes](https://github.com/dotnet/sqlclient/releases) - [Changelog](https://github.com/dotnet/SqlClient/blob/main/CHANGELOG.md) - [Commits](https://github.com/dotnet/sqlclient/compare/V5.2.0...v5.2.1) --- updated-dependencies: - dependency-name: Microsoft.Data.SqlClient dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .../Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj index 3d96d02..3a66b38 100644 --- a/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj +++ b/src/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer/Cnblogs.Architecture.Ddd.Cqrs.Dapper.SqlServer.csproj @@ -11,7 +11,7 @@ - + From ccb4d3869a0d89674b1cd2faddbb229898ffb819 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 02:39:18 +0000 Subject: [PATCH 7/9] chore(deps): bump MediatR from 12.2.0 to 12.3.0 Bumps [MediatR](https://github.com/jbogard/MediatR) from 12.2.0 to 12.3.0. - [Release notes](https://github.com/jbogard/MediatR/releases) - [Commits](https://github.com/jbogard/MediatR/compare/v12.2.0...v12.3.0) --- updated-dependencies: - dependency-name: MediatR dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../Cnblogs.Architecture.Ddd.Domain.Abstractions.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cnblogs.Architecture.Ddd.Domain.Abstractions/Cnblogs.Architecture.Ddd.Domain.Abstractions.csproj b/src/Cnblogs.Architecture.Ddd.Domain.Abstractions/Cnblogs.Architecture.Ddd.Domain.Abstractions.csproj index fbed1df..46a8849 100644 --- a/src/Cnblogs.Architecture.Ddd.Domain.Abstractions/Cnblogs.Architecture.Ddd.Domain.Abstractions.csproj +++ b/src/Cnblogs.Architecture.Ddd.Domain.Abstractions/Cnblogs.Architecture.Ddd.Domain.Abstractions.csproj @@ -14,7 +14,7 @@ - + From 56fa0aef5753f9998531a1100e3780c2837d2068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E6=98=9F=E7=B9=81?= Date: Sun, 16 Jun 2024 21:47:29 +0800 Subject: [PATCH 8/9] feat: enhance openapi support --- ...gs.Architecture.Ddd.Cqrs.AspNetCore.csproj | 1 + .../CqrsRouteMapper.cs | 88 ++++++++++++++----- .../EndPointExtensions.cs | 4 +- ...itecture.Ddd.Infrastructure.MongoDb.csproj | 2 +- .../Properties/launchSettings.json | 2 +- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore.csproj b/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore.csproj index f9e4092..f5b3a66 100644 --- a/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore.csproj +++ b/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/CqrsRouteMapper.cs b/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/CqrsRouteMapper.cs index ab233a3..2ab46a4 100644 --- a/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/CqrsRouteMapper.cs +++ b/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/CqrsRouteMapper.cs @@ -114,10 +114,10 @@ public static IEndpointConventionBuilder MapQuery( string nullRouteParameterPattern = "-", bool enableHead = false) { - var returnType = EnsureReturnTypeIsQuery(handler); + var (queryType, returnType) = EnsureReturnTypeIsQuery(handler); if (mapNullableRouteParameters is MapNullableRouteParameter.Disable) { - return MapRoutes(route); + return MapRoutes(queryType, returnType, route); } if (string.IsNullOrWhiteSpace(nullRouteParameterPattern)) @@ -129,7 +129,7 @@ public static IEndpointConventionBuilder MapQuery( var parsedRoute = RoutePatternFactory.Parse(route); var context = new NullabilityInfoContext(); - var nullableRouteProperties = returnType.GetProperties() + var nullableRouteProperties = queryType.GetProperties() .Where( p => p.GetMethod != null && p.SetMethod != null @@ -150,15 +150,24 @@ public static IEndpointConventionBuilder MapQuery( var regex = new Regex("{" + x.Name + "[^}]*?}", RegexOptions.IgnoreCase); return regex.Replace(r, nullRouteParameterPattern); }); - MapRoutes(newRoute); + MapRoutes(queryType, returnType, newRoute); } - return MapRoutes(route); + return MapRoutes(queryType, returnType, route); - IEndpointConventionBuilder MapRoutes(string r) + IEndpointConventionBuilder MapRoutes(Type query, Type queryFor, string r) { var endpoint = enableHead ? app.MapMethods(r, GetAndHeadMethods, handler) : app.MapGet(r, handler); - return endpoint.AddEndpointFilter(); + var builder = endpoint.AddEndpointFilter() + .Produces(200, queryFor) + .WithTags("Queries"); + if (query.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQuery<>))) + { + // may be null + builder.Produces(404, queryFor); + } + + return builder; } } @@ -220,7 +229,7 @@ public static IEndpointConventionBuilder MapCommand( [StringSyntax("Route")] string route, Delegate handler) { - var commandTypeName = EnsureReturnTypeIsCommand(handler).Name; + var commandTypeName = EnsureReturnTypeIsCommand(handler).CommandType.Name; if (PostCommandPrefixes.Any(x => commandTypeName.StartsWith(x))) { return app.MapPostCommand(route, handler); @@ -265,8 +274,11 @@ public static IEndpointConventionBuilder MapPostCommand( [StringSyntax("Route")] string route, Delegate handler) { - EnsureReturnTypeIsCommand(handler); - return app.MapPost(route, handler).AddEndpointFilter(); + var (commandType, responseType, errorType) = EnsureReturnTypeIsCommand(handler); + var builder = app.MapPost(route, handler) + .AddEndpointFilter() + .AddCommandOpenApiDescriptions(commandType, responseType, errorType); + return builder; } /// @@ -295,8 +307,9 @@ public static IEndpointConventionBuilder MapPutCommand( [StringSyntax("Route")] string route, Delegate handler) { - EnsureReturnTypeIsCommand(handler); - return app.MapPut(route, handler).AddEndpointFilter(); + var (commandType, responseType, errorType) = EnsureReturnTypeIsCommand(handler); + return app.MapPut(route, handler).AddEndpointFilter() + .AddCommandOpenApiDescriptions(commandType, responseType, errorType); } /// @@ -325,8 +338,9 @@ public static IEndpointConventionBuilder MapDeleteCommand( [StringSyntax("Route")] string route, Delegate handler) { - EnsureReturnTypeIsCommand(handler); - return app.MapDelete(route, handler).AddEndpointFilter(); + var (commandType, responseType, errorType) = EnsureReturnTypeIsCommand(handler); + return app.MapDelete(route, handler).AddEndpointFilter() + .AddCommandOpenApiDescriptions(commandType, responseType, errorType); } /// @@ -395,7 +409,7 @@ public static IEndpointRouteBuilder StopMappingPrefixToDelete(this IEndpointRout return app; } - private static Type EnsureReturnTypeIsCommand(Delegate handler) + private static (Type CommandType, Type? ResponseType, Type ErrorType) EnsureReturnTypeIsCommand(Delegate handler) { var returnType = handler.Method.ReturnType; if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) @@ -403,18 +417,24 @@ private static Type EnsureReturnTypeIsCommand(Delegate handler) returnType = returnType.GenericTypeArguments.First(); } - var isCommand = returnType.GetInterfaces().Where(x => x.IsGenericType) - .Any(x => CommandTypes.Contains(x.GetGenericTypeDefinition())); - if (isCommand == false) + var commandType = returnType.GetInterfaces().Where(x => x.IsGenericType) + .FirstOrDefault(x => CommandTypes.Contains(x.GetGenericTypeDefinition())); + if (commandType == null) { throw new ArgumentException( "handler does not return command, check if delegate returns type that implements ICommand<> or ICommand<,>"); } - return returnType; + Type?[] genericParams = commandType.GetGenericArguments(); + if (genericParams.Length == 1) + { + genericParams = [null, genericParams[0]]; + } + + return (returnType, genericParams[0], genericParams[1]!); } - private static Type EnsureReturnTypeIsQuery(Delegate handler) + private static (Type, Type) EnsureReturnTypeIsQuery(Delegate handler) { var returnType = handler.Method.ReturnType; if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) @@ -422,15 +442,15 @@ private static Type EnsureReturnTypeIsQuery(Delegate handler) returnType = returnType.GenericTypeArguments.First(); } - var isCommand = returnType.GetInterfaces().Where(x => x.IsGenericType) - .Any(x => QueryTypes.Contains(x.GetGenericTypeDefinition())); - if (isCommand == false) + var queryInterface = returnType.GetInterfaces().Where(x => x.IsGenericType) + .FirstOrDefault(x => QueryTypes.Contains(x.GetGenericTypeDefinition())); + if (queryInterface == null) { throw new ArgumentException( "handler does not return query, check if delegate returns type that implements IQuery<>"); } - return returnType; + return (returnType, queryInterface.GenericTypeArguments[0]); } private static List GetNotEmptySubsets(ICollection items) @@ -446,4 +466,24 @@ private static List GetNotEmptySubsets(ICollection items) return results; } + + private static RouteHandlerBuilder AddCommandOpenApiDescriptions( + this RouteHandlerBuilder builder, + Type commandType, + Type? responseType, + Type errorType) + { + var commandResponseType = responseType is null + ? typeof(CommandResponse<>).MakeGenericType(errorType) + : typeof(CommandResponse<,>).MakeGenericType(responseType, errorType); + builder.Produces(200, commandResponseType) + .Produces(400, commandResponseType) + .WithTags("Commands"); + if (commandType.GetInterfaces().Any(i => i == typeof(ILockableRequest))) + { + builder.Produces(429); + } + + return builder; + } } diff --git a/src/Cnblogs.Architecture.Ddd.EventBus.Dapr/EndPointExtensions.cs b/src/Cnblogs.Architecture.Ddd.EventBus.Dapr/EndPointExtensions.cs index 6d9ea3a..fb3923f 100644 --- a/src/Cnblogs.Architecture.Ddd.EventBus.Dapr/EndPointExtensions.cs +++ b/src/Cnblogs.Architecture.Ddd.EventBus.Dapr/EndPointExtensions.cs @@ -1,6 +1,7 @@ using System.Reflection; using Cnblogs.Architecture.Ddd.EventBus.Abstractions; using Cnblogs.Architecture.Ddd.EventBus.Dapr; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -58,7 +59,8 @@ public static IEndpointRouteBuilder Subscribe( builder .MapPost(route, (TEvent receivedEvent, IEventBus eventBus) => eventBus.ReceiveAsync(receivedEvent)) - .WithTopic(DaprOptions.PubSubName, DaprUtils.GetDaprTopicName(appName)); + .WithTopic(DaprOptions.PubSubName, DaprUtils.GetDaprTopicName(appName)) + .WithTags("Subscriptions"); return builder; } diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj b/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj index fdc9bb2..fec8fe0 100644 --- a/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj +++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb/Cnblogs.Architecture.Ddd.Infrastructure.MongoDb.csproj @@ -10,7 +10,7 @@ - + diff --git a/test/Cnblogs.Architecture.IntegrationTestProject/Properties/launchSettings.json b/test/Cnblogs.Architecture.IntegrationTestProject/Properties/launchSettings.json index 2b3e363..cc7ea7c 100644 --- a/test/Cnblogs.Architecture.IntegrationTestProject/Properties/launchSettings.json +++ b/test/Cnblogs.Architecture.IntegrationTestProject/Properties/launchSettings.json @@ -14,7 +14,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7200;http://localhost:5200", + "applicationUrl": "https://localhost:8200;http://localhost:5200", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From d35606bd01a7f115446c4690ca02b27261a88f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=88=E6=98=9F=E7=B9=81?= Date: Sun, 16 Jun 2024 22:44:01 +0800 Subject: [PATCH 9/9] feat: add redis cache provider --- Cnblogs.Architecture.sln | 7 ++ ...Infrastructure.CacheProviders.Redis.csproj | 18 ++++ .../Injectors.cs | 80 ++++++++++++++++++ .../RedisCacheProvider.cs | 84 +++++++++++++++++++ .../RedisOptions.cs | 24 ++++++ 5 files changed, 213 insertions(+) create mode 100644 src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj create mode 100644 src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Injectors.cs create mode 100644 src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisCacheProvider.cs create mode 100644 src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisOptions.cs diff --git a/Cnblogs.Architecture.sln b/Cnblogs.Architecture.sln index 2826a7b..520af13 100644 --- a/Cnblogs.Architecture.sln +++ b/Cnblogs.Architecture.sln @@ -62,6 +62,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.Architecture.Ddd.In EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.Architecture.Ddd.Infrastructure.FileProviders.AliyunOss", "src\Cnblogs.Architecture.Ddd.Infrastructure.FileProviders.AliyunOss\Cnblogs.Architecture.Ddd.Infrastructure.FileProviders.AliyunOss.csproj", "{9C76E136-1D79-408C-A17F-FD63632B00A9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis", "src\Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis\Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj", "{1FF58B65-6C83-4F0C-909A-6606B4C754B8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -94,6 +96,7 @@ Global {73665E32-3D10-4F71-B893-4C65F36332D0} = {D3A6DF01-017E-4088-936C-B3791F41DF53} {4BD98FBF-FB98-4172-B352-BB7BF8761FCB} = {D3A6DF01-017E-4088-936C-B3791F41DF53} {9C76E136-1D79-408C-A17F-FD63632B00A9} = {D3A6DF01-017E-4088-936C-B3791F41DF53} + {1FF58B65-6C83-4F0C-909A-6606B4C754B8} = {D3A6DF01-017E-4088-936C-B3791F41DF53} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {54D9D850-1CFC-485E-97FE-87F41C220523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -200,5 +203,9 @@ Global {9C76E136-1D79-408C-A17F-FD63632B00A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {9C76E136-1D79-408C-A17F-FD63632B00A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {9C76E136-1D79-408C-A17F-FD63632B00A9}.Release|Any CPU.Build.0 = Release|Any CPU + {1FF58B65-6C83-4F0C-909A-6606B4C754B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FF58B65-6C83-4F0C-909A-6606B4C754B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FF58B65-6C83-4F0C-909A-6606B4C754B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FF58B65-6C83-4F0C-909A-6606B4C754B8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj new file mode 100644 index 0000000..245d038 --- /dev/null +++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis.csproj @@ -0,0 +1,18 @@ + + + + + Provides remote cache provider that implemented with Redis + + + + + + + + + + + + + diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Injectors.cs b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Injectors.cs new file mode 100644 index 0000000..7b405cb --- /dev/null +++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/Injectors.cs @@ -0,0 +1,80 @@ +using Cnblogs.Architecture.Ddd.Cqrs.Abstractions; +using Cnblogs.Architecture.Ddd.Cqrs.DependencyInjection; +using Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using StackExchange.Redis; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Injectors for redis cache provider. +/// +public static class Injectors +{ + /// + /// Add redis cache as remote cache. + /// + /// The injector. + /// The root configuration. + /// The configuration section name for redis, defaults to Redis. + /// The optional configuration. + /// + public static CqrsInjector AddRedisCache( + this CqrsInjector injector, + IConfiguration configuration, + string sectionName = "Redis", + Action? configure = null) + { + return AddRedisCache(injector, configuration.GetSection(sectionName), configure); + } + + /// + /// Add redis cache as remote cache. + /// + /// The injector. + /// The configuration section for redis. + /// The optional configuration. + /// + public static CqrsInjector AddRedisCache( + this CqrsInjector injector, + IConfigurationSection section, + Action? configure = null) + { + injector.Services.Configure(section); + return AddRedisCache(injector, configure); + } + + /// + /// Add redis cache as remote cache. + /// + /// The injector. + /// The connection string. + /// Optional configuration for redis options. + /// The configure for cacheable request options. + /// + public static CqrsInjector AddRedisCache( + this CqrsInjector injector, + string connectionString, + Action? redisConfigure = null, + Action? configure = null) + { + var options = ConfigurationOptions.Parse(connectionString, true); + injector.Services.Configure(o => + { + o.Configure = options; + redisConfigure?.Invoke(o); + }); + return AddRedisCache(injector, configure); + } + + private static CqrsInjector AddRedisCache( + this CqrsInjector injector, + Action? configure = null) + { + injector.Services.AddSingleton( + sp => ConnectionMultiplexer.Connect(sp.GetRequiredService>().Value.Configure)); + return injector.AddRemoteQueryCache(configure); + } +} diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisCacheProvider.cs b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisCacheProvider.cs new file mode 100644 index 0000000..d17eae5 --- /dev/null +++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisCacheProvider.cs @@ -0,0 +1,84 @@ +using System.Text.Json; +using Cnblogs.Architecture.Ddd.Domain.Abstractions; +using Cnblogs.Architecture.Ddd.Infrastructure.Abstractions; +using Microsoft.Extensions.Options; +using StackExchange.Redis; + +namespace Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis; + +/// +/// Remote cache provider implemented with Redis. +/// +public class RedisCacheProvider + : IRemoteCacheProvider +{ + private readonly RedisOptions _options; + private readonly IDatabaseAsync _database; + private readonly IDateTimeProvider _dateTimeProvider; + + /// + /// Remote cache provider implemented with Redis. + /// + /// The underlying multiplexer. + /// The options for this provider. + /// The datetime provider. + public RedisCacheProvider( + ConnectionMultiplexer multiplexer, + IOptions options, + IDateTimeProvider dateTimeProvider) + { + _dateTimeProvider = dateTimeProvider; + _options = options.Value; + _database = multiplexer.GetDatabase(_options.Database); + } + + /// + public Task AddAsync(string cacheKey, TResult value) + { + return _database.StringSetAsync(GetCacheKey(cacheKey), Serialize(value)); + } + + /// + public Task AddAsync(string cacheKey, TimeSpan expires, TResult value) + { + return _database.StringSetAsync(GetCacheKey(cacheKey), Serialize(value), expires); + } + + /// + public async Task?> GetAsync(string cacheKey) + { + var json = await _database.StringGetAsync(GetCacheKey(cacheKey)); + if (json.IsNullOrEmpty) + { + return null; + } + + return DeSerialize(json!); + } + + /// + public Task RemoveAsync(string cacheKey) + { + return _database.KeyDeleteAsync(GetCacheKey(cacheKey)); + } + + /// + public Task UpdateAsync(string cacheKey, TResult value) + { + return AddAsync(cacheKey, value); + } + + /// + public Task UpdateAsync(string cacheKey, TResult value, TimeSpan expires) + { + return AddAsync(cacheKey, expires, value); + } + + private string GetCacheKey(string key) => $"{_options.Prefix}{key}"; + + private string Serialize(TResult result) + => JsonSerializer.Serialize(new CacheEntry(result, _dateTimeProvider.UnixSeconds())); + + private static CacheEntry? DeSerialize(string json) + => JsonSerializer.Deserialize>(json); +} diff --git a/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisOptions.cs b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisOptions.cs new file mode 100644 index 0000000..e021af3 --- /dev/null +++ b/src/Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis/RedisOptions.cs @@ -0,0 +1,24 @@ +using StackExchange.Redis; + +namespace Cnblogs.Architecture.Ddd.Infrastructure.CacheProviders.Redis; + +/// +/// Options for redis connection. +/// +public class RedisOptions +{ + /// + /// Prefix for all redis keys. + /// + public string Prefix { get; set; } = "cache_"; + + /// + /// The number of database to use. + /// + public int Database { get; set; } = -1; + + /// + /// The redis configuration, https://stackexchange.github.io/StackExchange.Redis/Configuration + /// + public ConfigurationOptions Configure { get; set; } = new(); +}