From 60f16ad1c4db0755960034a0cf0e7a538f970e4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E5=86=9B?= <510423039@qq.com>
Date: Wed, 26 Apr 2023 21:11:13 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3dotnetcore.cap=20?=
=?UTF-8?q?=E4=BA=8B=E5=8A=A1=E4=B8=80=E8=87=B4=E6=80=A7=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
aspnet-core/Lion.AbpPro.sln | 7 ++
.../GlobalUsings.cs | 13 ++++
...Lion.AbpPro.CAP.EntityFrameworkCore.csproj | 15 ++++
...fCoreLionAbpProCapTransactionApiFactory.cs | 64 ++++++++++++++++
.../ILionAbpProCapDbProviderInfoProvider.cs | 6 ++
.../LionAbpProCapDbProviderInfo.cs | 14 ++++
.../LionAbpProCapEntityFrameworkCoreModule.cs | 7 ++
.../LionAbpProCapOptionsExtensions.cs | 18 +++++
.../LionAbpProEfCoreDbContextCapOptions.cs | 6 ++
...bpProEfCoreDbContextCapOptionsExtension.cs | 14 ++++
...pProLionAbpProCapDbProviderInfoProvider.cs | 45 +++++++++++
.../ILionAbpProCapTransactionApiFactory.cs | 8 ++
.../LionAbpProCapConsumerServiceSelector.cs | 25 +++---
.../CAP/LionAbpProCapDistributedEventBus.cs | 76 ++++++++++++-------
.../Lion/AbpPro/CAP/LionAbpProCapModule.cs | 3 +-
.../CAP/LionAbpProCapPublisherExtension.cs | 11 +++
...ionAbpProCapServiceCollectionExtensions.cs | 13 +++-
.../AbpPro/CAP/LionAbpProCapUnitOfWork.cs | 51 +++++++++++++
.../AbpPro/CAP/LionAbpProJsonSerializer.cs | 67 ++++++++++++++++
.../Users/UserAppService.cs | 15 +++-
.../AbpProHttpApiHostModule.cs | 5 +-
.../Lion.AbpPro.HttpApi.Host.csproj | 1 +
22 files changed, 438 insertions(+), 46 deletions(-)
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/GlobalUsings.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion.AbpPro.CAP.EntityFrameworkCore.csproj
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/EfCoreLionAbpProCapTransactionApiFactory.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/ILionAbpProCapDbProviderInfoProvider.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapDbProviderInfo.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapEntityFrameworkCoreModule.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapOptionsExtensions.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptions.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptionsExtension.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProLionAbpProCapDbProviderInfoProvider.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/ILionAbpProCapTransactionApiFactory.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapPublisherExtension.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapUnitOfWork.cs
create mode 100644 aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProJsonSerializer.cs
diff --git a/aspnet-core/Lion.AbpPro.sln b/aspnet-core/Lion.AbpPro.sln
index 027e8fde..caaab4e4 100644
--- a/aspnet-core/Lion.AbpPro.sln
+++ b/aspnet-core/Lion.AbpPro.sln
@@ -240,6 +240,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lion.AbpPro.LanguageManagem
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lion.AbpPro.LanguageManagement.Application.Tests", "modules\LanguageManagement\test\Lion.AbpPro.LanguageManagement.Application.Tests\Lion.AbpPro.LanguageManagement.Application.Tests.csproj", "{15852D6F-4110-4B98-B89D-5747777E8908}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lion.AbpPro.CAP.EntityFrameworkCore", "frameworks\src\Lion.AbpPro.CAP.EntityFrameworkCore\Lion.AbpPro.CAP.EntityFrameworkCore.csproj", "{68C902A2-A604-4F3A-879D-37941C00C7A9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -582,6 +584,10 @@ Global
{15852D6F-4110-4B98-B89D-5747777E8908}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15852D6F-4110-4B98-B89D-5747777E8908}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15852D6F-4110-4B98-B89D-5747777E8908}.Release|Any CPU.Build.0 = Release|Any CPU
+ {68C902A2-A604-4F3A-879D-37941C00C7A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {68C902A2-A604-4F3A-879D-37941C00C7A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {68C902A2-A604-4F3A-879D-37941C00C7A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {68C902A2-A604-4F3A-879D-37941C00C7A9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -696,6 +702,7 @@ Global
{8872921C-5BF9-4B4C-B882-6AF8CC78D2CF} = {3FE23400-A323-46ED-A7F4-30BFF8916D64}
{E5994C85-C1C2-44F3-BF10-3277CA6CF2C9} = {3FE23400-A323-46ED-A7F4-30BFF8916D64}
{15852D6F-4110-4B98-B89D-5747777E8908} = {3FE23400-A323-46ED-A7F4-30BFF8916D64}
+ {68C902A2-A604-4F3A-879D-37941C00C7A9} = {7BE85EBC-99AD-4CDE-957E-4BDD087FC4E3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/GlobalUsings.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/GlobalUsings.cs
new file mode 100644
index 00000000..8b553ee8
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/GlobalUsings.cs
@@ -0,0 +1,13 @@
+// Global using directives
+
+global using System.Collections.Concurrent;
+global using DotNetCore.CAP;
+global using Microsoft.EntityFrameworkCore;
+global using Microsoft.EntityFrameworkCore.Storage;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Options;
+global using Volo.Abp.DependencyInjection;
+global using Volo.Abp.Modularity;
+global using Volo.Abp.Threading;
+global using Volo.Abp.Uow;
+global using Volo.Abp.Uow.EntityFrameworkCore;
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion.AbpPro.CAP.EntityFrameworkCore.csproj b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion.AbpPro.CAP.EntityFrameworkCore.csproj
new file mode 100644
index 00000000..dadd3608
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion.AbpPro.CAP.EntityFrameworkCore.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net7.0
+ enable
+
+ Lion.AbpPro.CAP.EntityFrameworkCore
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/EfCoreLionAbpProCapTransactionApiFactory.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/EfCoreLionAbpProCapTransactionApiFactory.cs
new file mode 100644
index 00000000..6fcefd26
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/EfCoreLionAbpProCapTransactionApiFactory.cs
@@ -0,0 +1,64 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore;
+
+public class EfCoreLionAbpProCapTransactionApiFactory : ILionAbpProCapTransactionApiFactory, ITransientDependency
+{
+ public Type TransactionApiType { get; } = typeof(EfCoreTransactionApi);
+
+ protected readonly ICapPublisher Publisher;
+ protected readonly LionAbpProEfCoreDbContextCapOptions Options;
+ protected readonly ILionAbpProCapDbProviderInfoProvider LionAbpProCapDbProviderInfoProvider;
+ protected readonly ICancellationTokenProvider CancellationTokenProvider;
+
+ public EfCoreLionAbpProCapTransactionApiFactory(
+ ICapPublisher publisher,
+ IOptions options,
+ ILionAbpProCapDbProviderInfoProvider lionAbpProCapDbProviderInfoProvider,
+ ICancellationTokenProvider cancellationTokenProvider)
+ {
+ Publisher = publisher;
+ Options = options.Value;
+ LionAbpProCapDbProviderInfoProvider = lionAbpProCapDbProviderInfoProvider;
+ CancellationTokenProvider = cancellationTokenProvider;
+ }
+
+ public virtual ITransactionApi Create(ITransactionApi originalApi)
+ {
+ var efApi = (EfCoreTransactionApi)originalApi;
+
+ var capTrans = CreateCapTransactionOrNull(efApi);
+
+ return capTrans is null
+ ? originalApi
+ : new EfCoreTransactionApi(capTrans, efApi.StarterDbContext, CancellationTokenProvider);
+ }
+
+ protected virtual IDbContextTransaction CreateCapTransactionOrNull(EfCoreTransactionApi originalApi)
+ {
+ // TODO 通过数据库连接字符串判断数据库类型
+ // if (Options.CapUsingDbConnectionString != originalApi.StarterDbContext.Database.GetConnectionString())
+ // {
+ // return null;
+ // }
+
+ var dbProviderInfo = LionAbpProCapDbProviderInfoProvider.GetOrNull(originalApi.StarterDbContext.Database.ProviderName);
+
+ if (dbProviderInfo?.CapTransactionType is null || dbProviderInfo.CapEfDbTransactionType is null)
+ {
+ return null;
+ }
+
+ var capTransactionType = dbProviderInfo.CapTransactionType;
+
+ if (ActivatorUtilities.CreateInstance(Publisher.ServiceProvider, capTransactionType) is not CapTransactionBase capTransaction)
+ {
+ return null;
+ }
+
+ capTransaction.DbTransaction = originalApi.DbContextTransaction;
+ capTransaction.AutoCommit = false;
+
+ Publisher.Transaction.Value = capTransaction;
+
+ return (IDbContextTransaction)Activator.CreateInstance(dbProviderInfo.CapEfDbTransactionType, capTransaction);
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/ILionAbpProCapDbProviderInfoProvider.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/ILionAbpProCapDbProviderInfoProvider.cs
new file mode 100644
index 00000000..f6aed69f
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/ILionAbpProCapDbProviderInfoProvider.cs
@@ -0,0 +1,6 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore;
+
+public interface ILionAbpProCapDbProviderInfoProvider
+{
+ LionAbpProCapDbProviderInfo GetOrNull(string dbProviderName);
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapDbProviderInfo.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapDbProviderInfo.cs
new file mode 100644
index 00000000..1cce7116
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapDbProviderInfo.cs
@@ -0,0 +1,14 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore;
+
+public class LionAbpProCapDbProviderInfo
+{
+ public Type CapTransactionType { get; }
+
+ public Type CapEfDbTransactionType { get; }
+
+ public LionAbpProCapDbProviderInfo(string capTransactionTypeName, string capEfDbTransactionTypeName)
+ {
+ CapTransactionType = Type.GetType(capTransactionTypeName, false);
+ CapEfDbTransactionType = Type.GetType(capEfDbTransactionTypeName, false);
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapEntityFrameworkCoreModule.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapEntityFrameworkCoreModule.cs
new file mode 100644
index 00000000..787bba48
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapEntityFrameworkCoreModule.cs
@@ -0,0 +1,7 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore
+{
+ [DependsOn(typeof(LionAbpProCapModule))]
+ public class LionAbpProCapEntityFrameworkCoreModule : AbpModule
+ {
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapOptionsExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapOptionsExtensions.cs
new file mode 100644
index 00000000..43f219f1
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProCapOptionsExtensions.cs
@@ -0,0 +1,18 @@
+using Lion.AbpPro.CAP.EntityFrameworkCore;
+
+// ReSharper disable once CheckNamespace
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public static class LionAbpProCapOptionsExtensions
+ {
+ public static CapOptions SetCapDbConnectionString(this CapOptions options, string dbConnectionString)
+ {
+ options.RegisterExtension(new LionAbpProEfCoreDbContextCapOptionsExtension
+ {
+ CapUsingDbConnectionString = dbConnectionString
+ });
+
+ return options;
+ }
+ }
+}
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptions.cs
new file mode 100644
index 00000000..bc30551d
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptions.cs
@@ -0,0 +1,6 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore;
+
+public class LionAbpProEfCoreDbContextCapOptions
+{
+ public string CapUsingDbConnectionString { get; set; }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptionsExtension.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptionsExtension.cs
new file mode 100644
index 00000000..b28a1f07
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProEfCoreDbContextCapOptionsExtension.cs
@@ -0,0 +1,14 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore;
+
+public class LionAbpProEfCoreDbContextCapOptionsExtension : ICapOptionsExtension
+{
+ public string CapUsingDbConnectionString { get; init; }
+
+ public void AddServices(IServiceCollection services)
+ {
+ services.Configure(options =>
+ {
+ options.CapUsingDbConnectionString = CapUsingDbConnectionString;
+ });
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProLionAbpProCapDbProviderInfoProvider.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProLionAbpProCapDbProviderInfoProvider.cs
new file mode 100644
index 00000000..ec610c22
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP.EntityFrameworkCore/Lion/AbpPro/CAP/EntityFrameworkCore/LionAbpProLionAbpProCapDbProviderInfoProvider.cs
@@ -0,0 +1,45 @@
+namespace Lion.AbpPro.CAP.EntityFrameworkCore;
+
+public class LionAbpProLionAbpProCapDbProviderInfoProvider : ILionAbpProCapDbProviderInfoProvider, ITransientDependency
+{
+ protected ConcurrentDictionary CapDbProviderInfos { get; set; } = new();
+
+ public virtual LionAbpProCapDbProviderInfo GetOrNull(string dbProviderName)
+ {
+ return CapDbProviderInfos.GetOrAdd(dbProviderName, InternalGetOrNull);
+ }
+
+ protected virtual LionAbpProCapDbProviderInfo InternalGetOrNull(string databaseProviderName)
+ {
+ switch (databaseProviderName)
+ {
+ case "Microsoft.EntityFrameworkCore.SqlServer":
+ return new LionAbpProCapDbProviderInfo(
+ "DotNetCore.CAP.SqlServerCapTransaction, DotNetCore.CAP.SqlServer",
+ "Microsoft.EntityFrameworkCore.Storage.CapEFDbTransaction, DotNetCore.CAP.SqlServer");
+ case "Npgsql.EntityFrameworkCore.PostgreSQL":
+ return new LionAbpProCapDbProviderInfo(
+ "DotNetCore.CAP.PostgreSqlCapTransaction, DotNetCore.CAP.PostgreSql",
+ "Microsoft.EntityFrameworkCore.Storage.CapEFDbTransaction, DotNetCore.CAP.PostgreSQL");
+ case "Pomelo.EntityFrameworkCore.MySql":
+ return new LionAbpProCapDbProviderInfo(
+ "DotNetCore.CAP.MySqlCapTransaction, DotNetCore.CAP.MySql",
+ "Microsoft.EntityFrameworkCore.Storage.CapEFDbTransaction, DotNetCore.CAP.MySql");
+ case "Oracle.EntityFrameworkCore":
+ case "Devart.Data.Oracle.Entity.EFCore":
+ return new LionAbpProCapDbProviderInfo(
+ "DotNetCore.CAP.OracleCapTransaction, DotNetCore.CAP.Oracle",
+ "Microsoft.EntityFrameworkCore.Storage.CapEFDbTransaction, DotNetCore.CAP.Oracle");
+ case "Microsoft.EntityFrameworkCore.Sqlite":
+ return new LionAbpProCapDbProviderInfo(
+ "DotNetCore.CAP.SqliteCapTransaction, DotNetCore.CAP.Sqlite",
+ "Microsoft.EntityFrameworkCore.Storage.CapEFDbTransaction, DotNetCore.CAP.Sqlite");
+ case "Microsoft.EntityFrameworkCore.InMemory":
+ return new LionAbpProCapDbProviderInfo(
+ "DotNetCore.CAP.InMemoryCapTransaction, DotNetCore.CAP.InMemoryStorage",
+ "Microsoft.EntityFrameworkCore.Storage.CapEFDbTransaction, DotNetCore.CAP.InMemoryStorage");
+ default:
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/ILionAbpProCapTransactionApiFactory.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/ILionAbpProCapTransactionApiFactory.cs
new file mode 100644
index 00000000..5f311061
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/ILionAbpProCapTransactionApiFactory.cs
@@ -0,0 +1,8 @@
+namespace Lion.AbpPro.CAP;
+
+public interface ILionAbpProCapTransactionApiFactory
+{
+ Type TransactionApiType { get; }
+
+ ITransactionApi Create(ITransactionApi originalApi);
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapConsumerServiceSelector.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapConsumerServiceSelector.cs
index ac4d7ece..652e055e 100644
--- a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapConsumerServiceSelector.cs
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapConsumerServiceSelector.cs
@@ -1,19 +1,14 @@
namespace Lion.AbpPro.CAP;
-[Dependency(ServiceLifetime.Singleton, ReplaceServices = true)]
-[ExposeServices(typeof(IConsumerServiceSelector))]
-public sealed class LionAbpProCapConsumerServiceSelector : ConsumerServiceSelector
+public class LionAbpProCapConsumerServiceSelector : ConsumerServiceSelector, ISingletonDependency
{
- private AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
- private IServiceProvider ServiceProvider { get; }
+ protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
+ protected IServiceProvider ServiceProvider { get; }
///
/// Creates a new .
///
- public LionAbpProCapConsumerServiceSelector(
- IServiceProvider serviceProvider,
- IOptions distributedEventBusOptions)
- : base(serviceProvider)
+ public LionAbpProCapConsumerServiceSelector(IServiceProvider serviceProvider, IOptions distributedEventBusOptions) : base(serviceProvider)
{
ServiceProvider = serviceProvider;
AbpDistributedEventBusOptions = distributedEventBusOptions.Value;
@@ -22,7 +17,7 @@ public sealed class LionAbpProCapConsumerServiceSelector : ConsumerServiceSelect
protected override IEnumerable FindConsumersFromInterfaceTypes(IServiceProvider provider)
{
var executorDescriptorList = base.FindConsumersFromInterfaceTypes(provider).ToList();
-
+
//handlers
var handlers = AbpDistributedEventBusOptions.Handlers;
@@ -35,8 +30,9 @@ public sealed class LionAbpProCapConsumerServiceSelector : ConsumerServiceSelect
{
continue;
}
+
var genericArgs = @interface.GetGenericArguments();
-
+
if (genericArgs.Length != 1)
{
continue;
@@ -51,17 +47,18 @@ public sealed class LionAbpProCapConsumerServiceSelector : ConsumerServiceSelect
descriptor.Attribute.Group = descriptor.Attribute.Group.Insert(
descriptor.Attribute.Group.LastIndexOf(".", StringComparison.Ordinal), $".{count}");
-
+
executorDescriptorList.Add(descriptor);
}
-
+
//Subscribe(genericArgs[0], new IocEventHandlerFactory(ServiceScopeFactory, handler));
}
}
+
return executorDescriptorList;
}
- private IEnumerable GetHandlerDescription(Type eventType,Type typeInfo)
+ protected virtual IEnumerable GetHandlerDescription(Type eventType, Type typeInfo)
{
var serviceTypeInfo = typeof(IDistributedEventHandler<>)
.MakeGenericType(eventType);
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapDistributedEventBus.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapDistributedEventBus.cs
index 11a310d4..337a9c3f 100644
--- a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapDistributedEventBus.cs
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapDistributedEventBus.cs
@@ -1,24 +1,21 @@
namespace Lion.AbpPro.CAP;
-public class LionAbpProCapDistributedEventBus :
- EventBusBase,
- IDistributedEventBus,
- ISingletonDependency
+public class LionAbpProCapDistributedEventBus : EventBusBase, IDistributedEventBus, ISingletonDependency
{
- private AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
- private ConcurrentDictionary> HandlerFactories { get; }
- private ConcurrentDictionary EventTypes { get; }
+ protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
+ protected readonly ICapPublisher CapPublisher;
- private readonly ICapPublisher CapPublisher;
+ //TODO: Accessing to the List may not be thread-safe!
+ protected ConcurrentDictionary> HandlerFactories { get; }
+ protected ConcurrentDictionary EventTypes { get; }
-
public LionAbpProCapDistributedEventBus(IServiceScopeFactory serviceScopeFactory,
IOptions distributedEventBusOptions,
ICapPublisher capPublisher,
+ IUnitOfWorkManager unitOfWorkManager,
ICurrentTenant currentTenant,
- UnitOfWorkManager unitOfWorkManager,
IEventHandlerInvoker eventHandlerInvoker)
- : base(serviceScopeFactory, currentTenant,unitOfWorkManager,eventHandlerInvoker)
+ : base(serviceScopeFactory, currentTenant, unitOfWorkManager, eventHandlerInvoker)
{
CapPublisher = capPublisher;
AbpDistributedEventBusOptions = distributedEventBusOptions.Value;
@@ -82,36 +79,63 @@ public class LionAbpProCapDistributedEventBus :
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
- protected override Task PublishToEventBusAsync(Type eventType, object eventData)
+ public IDisposable Subscribe(IDistributedEventHandler handler) where TEvent : class
{
- throw new NotImplementedException();
+ return Subscribe(typeof(TEvent), handler);
}
- protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord)
+ public virtual Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true,
+ bool useOutbox = true) where TEvent : class
{
- throw new NotImplementedException();
+ return PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete, useOutbox);
}
- public IDisposable Subscribe(IDistributedEventHandler handler) where TEvent : class
+ public virtual async Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true,
+ bool useOutbox = true)
{
- return Subscribe(typeof(TEvent), handler);
- }
+ if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null)
+ {
+ AddToUnitOfWork(
+ UnitOfWorkManager.Current,
+ new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext(), useOutbox)
+ );
+ return;
+ }
- public async Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true,
- bool useOutbox = true) where TEvent : class
- {
- var eventName = EventNameAttribute.GetNameOrDefault(typeof(TEvent));
- await CapPublisher.PublishAsync(eventName, eventData);
+ if (useOutbox && UnitOfWorkManager.Current != null)
+ {
+ if (UnitOfWorkManager.Current is not LionAbpProCapUnitOfWork capUnitOfWork || capUnitOfWork.CapTransaction is null)
+ {
+ UnitOfWorkManager.Current.OnCompleted(async () =>
+ {
+ await PublishToEventBusAsync(eventType, eventData);
+ });
+ }
+ else
+ {
+ using (CapPublisher.UseTransaction(capUnitOfWork.CapTransaction))
+ {
+ // Use CAP transactional outbox
+ await PublishToEventBusAsync(eventType, eventData);
+ }
+ }
+ return;
+ }
+
+ await PublishToEventBusAsync(eventType, eventData);
}
- public async Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true,
- bool useOutbox = true)
+ protected override async Task PublishToEventBusAsync(Type eventType, object eventData)
{
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
await CapPublisher.PublishAsync(eventName, eventData);
}
-
+
+ protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord)
+ {
+ unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
+ }
protected override IEnumerable GetHandlerFactories(Type eventType)
{
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapModule.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapModule.cs
index a9c5e779..c530c2a3 100644
--- a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapModule.cs
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapModule.cs
@@ -2,7 +2,8 @@ namespace Lion.AbpPro.CAP;
[DependsOn(
typeof(AbpEventBusModule),
- typeof(LionAbpProLocalizationModule))]
+ typeof(LionAbpProLocalizationModule),
+ typeof(AbpUnitOfWorkModule))]
public class LionAbpProCapModule : AbpModule
{
}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapPublisherExtension.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapPublisherExtension.cs
new file mode 100644
index 00000000..c3d68dcf
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapPublisherExtension.cs
@@ -0,0 +1,11 @@
+namespace Lion.AbpPro.CAP;
+
+public static class LionAbpProCapPublisherExtension
+{
+ public static IDisposable UseTransaction(this ICapPublisher capPublisher, ICapTransaction capTransaction)
+ {
+ var previousValue = capPublisher.Transaction.Value;
+ capPublisher.Transaction.Value = capTransaction;
+ return new DisposeAction(() => capPublisher.Transaction.Value = previousValue);
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapServiceCollectionExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapServiceCollectionExtensions.cs
index a85b754f..ea81c2ce 100644
--- a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapServiceCollectionExtensions.cs
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapServiceCollectionExtensions.cs
@@ -1,3 +1,6 @@
+using DotNetCore.CAP.Serialization;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
namespace Lion.AbpPro.CAP;
public static class LionAbpProCapServiceCollectionExtensions
@@ -6,9 +9,15 @@ public static class LionAbpProCapServiceCollectionExtensions
this ServiceConfigurationContext context,
Action capAction)
{
+ // context.Services.AddSingleton();
+ // context.Services.AddSingleton();
+ // context.Services.AddSingleton();
+
+ context.Services.Replace(ServiceDescriptor.Transient());
+ context.Services.Replace(ServiceDescriptor.Transient());
+ context.Services.AddTransient();
+
context.Services.AddCap(capAction);
- context.Services.AddSingleton();
- context.Services.AddSingleton();
return context;
}
}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapUnitOfWork.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapUnitOfWork.cs
new file mode 100644
index 00000000..6e4bec2b
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProCapUnitOfWork.cs
@@ -0,0 +1,51 @@
+namespace Lion.AbpPro.CAP;
+
+[Dependency(TryRegister = true)]
+public class LionAbpProCapUnitOfWork : UnitOfWork
+{
+ public ICapTransaction CapTransaction { get; protected set; }
+
+ protected ICapPublisher CapPublisher { get; }
+
+ public LionAbpProCapUnitOfWork(
+ IServiceProvider serviceProvider,
+ IUnitOfWorkEventPublisher unitOfWorkEventPublisher,
+ IOptions options,
+ ICapPublisher capPublisher)
+ : base(serviceProvider, unitOfWorkEventPublisher, options)
+ {
+ CapPublisher = capPublisher;
+ }
+
+ public override void AddTransactionApi(string key, ITransactionApi api)
+ {
+ var factories = ServiceProvider.GetServices();
+
+ var factory = factories.FirstOrDefault(x => x.TransactionApiType == api.GetType());
+
+ if (factory is not null)
+ {
+ api = factory.Create(api);
+ CapTransaction = CapPublisher.Transaction.Value;
+ }
+
+ base.AddTransactionApi(key, api);
+ }
+
+ public override ITransactionApi GetOrAddTransactionApi(string key, Func factory)
+ {
+ Check.NotNull(key, nameof(key));
+ Check.NotNull(factory, nameof(factory));
+
+ var transactionApi = FindTransactionApi(key);
+
+ if (transactionApi is not null)
+ {
+ return transactionApi;
+ }
+
+ AddTransactionApi(key, factory());
+
+ return FindTransactionApi(key);
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProJsonSerializer.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProJsonSerializer.cs
new file mode 100644
index 00000000..4d146194
--- /dev/null
+++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/LionAbpProJsonSerializer.cs
@@ -0,0 +1,67 @@
+using System.Text;
+using System.Text.Json;
+using DotNetCore.CAP.Messages;
+using DotNetCore.CAP.Serialization;
+using Volo.Abp.Json;
+
+namespace Lion.AbpPro.CAP;
+
+public class LionAbpProJsonSerializer : ISerializer, ISingletonDependency
+{
+ private readonly IJsonSerializer _jsonSerializer;
+
+ public LionAbpProJsonSerializer(IJsonSerializer jsonSerializer)
+ {
+ _jsonSerializer = jsonSerializer;
+ }
+
+ public virtual string Serialize(Message message)
+ {
+ return _jsonSerializer.Serialize(message);
+ }
+
+ public virtual ValueTask SerializeAsync(Message message)
+ {
+ if (message == null)
+ {
+ throw new ArgumentNullException(nameof(message));
+ }
+
+ if (message.Value == null)
+ {
+ return new ValueTask(new TransportMessage(message.Headers, null));
+ }
+
+ var json = _jsonSerializer.Serialize(message.Value);
+
+ return new ValueTask(new TransportMessage(message.Headers, Encoding.UTF8.GetBytes(json)));
+ }
+
+ public virtual Message Deserialize(string json)
+ {
+ return _jsonSerializer.Deserialize(json);
+ }
+
+ public virtual ValueTask DeserializeAsync(TransportMessage transportMessage, Type valueType)
+ {
+ if (valueType == null || transportMessage.Body.IsEmpty)
+ {
+ return new ValueTask(new Message(transportMessage.Headers, null));
+ }
+
+ var json = Encoding.UTF8.GetString(transportMessage.Body.ToArray());
+
+ return new ValueTask(new Message(transportMessage.Headers,
+ _jsonSerializer.Deserialize(valueType, json)));
+ }
+
+ public virtual object Deserialize(object value, Type valueType)
+ {
+ return _jsonSerializer.Deserialize(valueType, value.ToString());
+ }
+
+ public virtual bool IsJsonType(object jsonObject)
+ {
+ return jsonObject is JsonElement;
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application/Users/UserAppService.cs b/aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application/Users/UserAppService.cs
index 3496f171..f499c0be 100644
--- a/aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application/Users/UserAppService.cs
+++ b/aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application/Users/UserAppService.cs
@@ -4,6 +4,7 @@ using Magicodes.ExporterAndImporter.Excel.AspNetCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Account;
+using Volo.Abp.Uow;
using IdentityRole = Volo.Abp.Identity.IdentityRole;
namespace Lion.AbpPro.BasicManagement.Users
@@ -80,7 +81,12 @@ namespace Lion.AbpPro.BasicManagement.Users
{
// abp 5.0 之后新增字段,是否运行用户登录,默认设置为true
input.IsActive = true;
- return await _identityUserAppService.CreateAsync(input);
+ using (var uow = UnitOfWorkManager.Begin(new AbpUnitOfWorkOptions() { IsTransactional = true }, true))
+ {
+ await _identityUserAppService.CreateAsync(input);
+ await uow.CompleteAsync();
+ }
+ return null;
}
///
@@ -90,7 +96,12 @@ namespace Lion.AbpPro.BasicManagement.Users
public virtual async Task UpdateAsync(UpdateUserInput input)
{
input.UserInfo.IsActive = true;
- return await _identityUserAppService.UpdateAsync(input.UserId, input.UserInfo);
+ using (var uow = UnitOfWorkManager.Begin(new AbpUnitOfWorkOptions() { IsTransactional = true }, true))
+ {
+ await _identityUserAppService.UpdateAsync(input.UserId, input.UserInfo);
+ }
+
+ return null;
}
///
diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs
index 3400f2a5..42897c77 100644
--- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs
+++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs
@@ -1,4 +1,5 @@
using Hangfire.Redis;
+using Lion.AbpPro.CAP.EntityFrameworkCore;
using Swagger;
using Volo.Abp.BackgroundJobs.Hangfire;
using Volo.Abp.Timing;
@@ -15,6 +16,7 @@ namespace Lion.AbpPro
typeof(AbpAccountWebModule),
typeof(AbpProApplicationModule),
typeof(LionAbpProCapModule),
+ typeof(LionAbpProCapEntityFrameworkCoreModule),
typeof(AbpAspNetCoreMvcUiBasicThemeModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpBackgroundJobsHangfireModule)
@@ -302,6 +304,7 @@ namespace Lion.AbpPro
{
context.AddAbpCap(capOptions =>
{
+ capOptions.SetCapDbConnectionString(configuration["ConnectionStrings:Default"]);
capOptions.UseEntityFramework();
capOptions.UseRabbitMQ(option =>
{
@@ -326,7 +329,7 @@ namespace Lion.AbpPro
capOptions.UseInMemoryStorage();
capOptions.UseInMemoryMessageQueue();
var hostingEnvironment = context.Services.GetHostingEnvironment();
- bool auth = !hostingEnvironment.IsDevelopment();
+ var auth = !hostingEnvironment.IsDevelopment();
capOptions.UseDashboard(options => { options.UseAuth = auth; });
});
}
diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj
index 9184032f..b0b08547 100644
--- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj
+++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj
@@ -44,6 +44,7 @@
+