From 819a4488bacb2dd58c8d5ae236fe09101441a1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Feb 2021 09:55:40 +0300 Subject: [PATCH] Implemented #7737 for MongoDB: Should return the same instance in th same UOW for replaced DbContexts. --- .../AbpDbContextOptions.cs | 15 +++++-- .../EntityFrameworkCore/EfCoreDatabaseApi.cs | 1 - .../Volo/Abp/MemoryDb/AbpMemoryDbModule.cs | 1 - .../AbpMongoDbServiceCollectionExtensions.cs | 15 +++++++ .../Properties/AssemblyInfo.cs | 2 + .../Abp/MongoDB/AbpMongoDbContextOptions.cs | 39 +++++++++++++++++++ .../Abp/Uow/MongoDB/MongoDbDatabaseApi.cs | 10 +++-- .../UnitOfWorkMongoDbContextProvider.cs | 20 ++++++---- .../TestApp/MongoDb/TestAppMongoDbContext.cs | 2 +- 9 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs index e3326ac7c5..92c6935900 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContextOptions.cs @@ -63,15 +63,24 @@ namespace Volo.Abp.EntityFrameworkCore internal Type GetReplacedTypeOrSelf(Type dbContextType) { + var replacementType = dbContextType; while (true) { - if (DbContextReplacements.TryGetValue(dbContextType, out var foundType)) + if (DbContextReplacements.TryGetValue(replacementType, out var foundType)) { - dbContextType = foundType; + if (foundType == dbContextType) + { + throw new AbpException( + "Circular DbContext replacement found for " + + dbContextType.AssemblyQualifiedName + ); + } + + replacementType = foundType; } else { - return dbContextType; + return replacementType; } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreDatabaseApi.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreDatabaseApi.cs index 88a2428318..151d78e255 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreDatabaseApi.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/EfCoreDatabaseApi.cs @@ -1,6 +1,5 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.Uow.EntityFrameworkCore diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/AbpMemoryDbModule.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/AbpMemoryDbModule.cs index bd8b4b98a4..5452abba03 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/AbpMemoryDbModule.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/AbpMemoryDbModule.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Domain; using Volo.Abp.Domain.Repositories.MemoryDb; -using Volo.Abp.Json; using Volo.Abp.Modularity; using Volo.Abp.Uow.MemoryDb; diff --git a/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs b/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs index 1ad31d2de9..5adf7300ee 100644 --- a/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs @@ -17,6 +17,21 @@ namespace Microsoft.Extensions.DependencyInjection { services.Replace(ServiceDescriptor.Transient(dbContextType, typeof(TMongoDbContext))); } + + foreach (var dbContextType in options.ReplacedDbContextTypes) + { + services.Replace( + ServiceDescriptor.Transient( + dbContextType, + sp => sp.GetRequiredService(typeof(TMongoDbContext)) + ) + ); + + services.Configure(opts => + { + opts.DbContextReplacements[dbContextType] = typeof(TMongoDbContext); + }); + } new MongoDbRepositoryRegistrar(options).AddRepositories(); diff --git a/framework/src/Volo.Abp.MongoDB/Properties/AssemblyInfo.cs b/framework/src/Volo.Abp.MongoDB/Properties/AssemblyInfo.cs index 51745424f2..77656ec064 100644 --- a/framework/src/Volo.Abp.MongoDB/Properties/AssemblyInfo.cs +++ b/framework/src/Volo.Abp.MongoDB/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -8,6 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Volo.Abp.MongoDB")] [assembly: AssemblyTrademark("")] +[assembly: InternalsVisibleTo("Volo.Abp.MongoDB.Tests")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs new file mode 100644 index 0000000000..aaee9571cd --- /dev/null +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContextOptions.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.MongoDB +{ + public class AbpMongoDbContextOptions + { + internal Dictionary DbContextReplacements { get; } + + public AbpMongoDbContextOptions() + { + DbContextReplacements = new Dictionary(); + } + + internal Type GetReplacedTypeOrSelf(Type dbContextType) + { + var replacementType = dbContextType; + while (true) + { + if (DbContextReplacements.TryGetValue(replacementType, out var foundType)) + { + if (foundType == dbContextType) + { + throw new AbpException( + "Circular DbContext replacement found for " + + dbContextType.AssemblyQualifiedName + ); + } + + replacementType = foundType; + } + else + { + return replacementType; + } + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/MongoDbDatabaseApi.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/MongoDbDatabaseApi.cs index bb02ad0108..c1beda98aa 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/MongoDbDatabaseApi.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/MongoDbDatabaseApi.cs @@ -1,10 +1,12 @@ -namespace Volo.Abp.Uow.MongoDB +using Volo.Abp.MongoDB; + +namespace Volo.Abp.Uow.MongoDB { - public class MongoDbDatabaseApi : IDatabaseApi + public class MongoDbDatabaseApi : IDatabaseApi { - public TMongoDbContext DbContext { get; } + public IAbpMongoDbContext DbContext { get; } - public MongoDbDatabaseApi(TMongoDbContext dbContext) + public MongoDbDatabaseApi(IAbpMongoDbContext dbContext) { DbContext = dbContext; } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs index 684593fb7f..a26307234d 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using Volo.Abp.Data; @@ -22,17 +23,20 @@ namespace Volo.Abp.Uow.MongoDB private readonly IConnectionStringResolver _connectionStringResolver; private readonly ICancellationTokenProvider _cancellationTokenProvider; private readonly ICurrentTenant _currentTenant; + private readonly AbpMongoDbContextOptions _options; public UnitOfWorkMongoDbContextProvider( IUnitOfWorkManager unitOfWorkManager, IConnectionStringResolver connectionStringResolver, ICancellationTokenProvider cancellationTokenProvider, - ICurrentTenant currentTenant) + ICurrentTenant currentTenant, + IOptions options) { _unitOfWorkManager = unitOfWorkManager; _connectionStringResolver = connectionStringResolver; _cancellationTokenProvider = cancellationTokenProvider; _currentTenant = currentTenant; + _options = options.Value; Logger = NullLogger>.Instance; } @@ -59,7 +63,8 @@ namespace Volo.Abp.Uow.MongoDB } var connectionString = ResolveConnectionString(); - var dbContextKey = $"{typeof(TMongoDbContext).FullName}_{connectionString}"; + var targetDbContextType = _options.GetReplacedTypeOrSelf(typeof(TMongoDbContext)); + var dbContextKey = $"{targetDbContextType.FullName}_{connectionString}"; var mongoUrl = new MongoUrl(connectionString); var databaseName = mongoUrl.DatabaseName; @@ -71,9 +76,9 @@ namespace Volo.Abp.Uow.MongoDB //TODO: Create only single MongoDbClient per connection string in an application (extract MongoClientCache for example). var databaseApi = unitOfWork.GetOrAddDatabaseApi( dbContextKey, - () => new MongoDbDatabaseApi(CreateDbContext(unitOfWork, mongoUrl, databaseName))); + () => new MongoDbDatabaseApi(CreateDbContext(unitOfWork, mongoUrl, databaseName))); - return ((MongoDbDatabaseApi) databaseApi).DbContext; + return (TMongoDbContext)((MongoDbDatabaseApi) databaseApi).DbContext; } public async Task GetDbContextAsync(CancellationToken cancellationToken = default) @@ -86,7 +91,8 @@ namespace Volo.Abp.Uow.MongoDB } var connectionString = await ResolveConnectionStringAsync(); - var dbContextKey = $"{typeof(TMongoDbContext).FullName}_{connectionString}"; + var targetDbContextType = _options.GetReplacedTypeOrSelf(typeof(TMongoDbContext)); + var dbContextKey = $"{targetDbContextType.FullName}_{connectionString}"; var mongoUrl = new MongoUrl(connectionString); var databaseName = mongoUrl.DatabaseName; @@ -99,7 +105,7 @@ namespace Volo.Abp.Uow.MongoDB var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey); if (databaseApi == null) { - databaseApi = new MongoDbDatabaseApi( + databaseApi = new MongoDbDatabaseApi( await CreateDbContextAsync( unitOfWork, mongoUrl, @@ -111,7 +117,7 @@ namespace Volo.Abp.Uow.MongoDB unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); } - return ((MongoDbDatabaseApi) databaseApi).DbContext; + return (TMongoDbContext)((MongoDbDatabaseApi) databaseApi).DbContext; } [Obsolete("Use CreateDbContextAsync")] diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs index 03869ce566..eed8d4ade3 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.TestApp.MongoDB public IMongoCollection Cities => Collection(); - protected override void CreateModel(IMongoModelBuilder modelBuilder) + protected internal override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder);