using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using MongoDB.Driver; using System; using System.Threading; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Data; using Volo.Abp.MongoDB; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; using Volo.Abp.Uow; namespace Bussiness.MongoDB { /// /// 自定义MongoDB上下文提供程序,禁用事务支持 /// 用于解决Standalone MongoDB服务器不支持事务的问题 /// public class NonTransactionalMongoDbContextProvider : IMongoDbContextProvider where TMongoDbContext : class, IAbpMongoDbContext { private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IConnectionStringResolver _connectionStringResolver; private readonly ICancellationTokenProvider _cancellationTokenProvider; private readonly ICurrentTenant _currentTenant; private readonly IServiceProvider _serviceProvider; private readonly ILogger> _logger; public NonTransactionalMongoDbContextProvider( IUnitOfWorkManager unitOfWorkManager, IConnectionStringResolver connectionStringResolver, ICancellationTokenProvider cancellationTokenProvider, ICurrentTenant currentTenant, IServiceProvider serviceProvider, ILogger> logger) { _unitOfWorkManager = unitOfWorkManager; _connectionStringResolver = connectionStringResolver; _cancellationTokenProvider = cancellationTokenProvider; _currentTenant = currentTenant; _serviceProvider = serviceProvider; _logger = logger; } public async Task GetDbContextAsync(CancellationToken cancellationToken = default) { var unitOfWork = _unitOfWorkManager.Current; if (unitOfWork == null) { throw new AbpException("A DbContext can only be created inside a unit of work!"); } var targetTenantId = _currentTenant.Id; var connectionString = await ResolveConnectionStringAsync(targetTenantId); var dbContextKey = $"{typeof(TMongoDbContext).FullName}_{connectionString}"; var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey); if (databaseApi == null) { // 创建不带事务的数据库API databaseApi = new MongoDbDatabaseApi(await CreateDbContextAsync(unitOfWork, connectionString, cancellationToken)); unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); } return ((MongoDbDatabaseApi)databaseApi).DbContext.As(); } [Obsolete("Use GetDbContextAsync method.")] public TMongoDbContext GetDbContext() { return AsyncHelper.RunSync(() => GetDbContextAsync()); } private Task CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionString, CancellationToken cancellationToken) { var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); var mongoUrl = new MongoUrl(connectionString); var databaseName = mongoUrl.DatabaseName; if (databaseName.IsNullOrWhiteSpace()) { databaseName = ConnectionStringNameAttribute.GetConnStringName(); } // 创建MongoDB客户端(不使用事务) var client = new MongoClient(mongoUrl); var database = client.GetDatabase(databaseName); // 初始化DbContext,不传入session(即不使用事务) dbContext.ToAbpMongoDbContext().InitializeDatabase(database, client, null); _logger.LogDebug("MongoDB context created without transaction support for standalone server."); return Task.FromResult(dbContext); } private async Task ResolveConnectionStringAsync(Guid? tenantId) { if (tenantId == _currentTenant.Id) { return await _connectionStringResolver.ResolveAsync(ConnectionStringNameAttribute.GetConnStringName()); } using (_currentTenant.Change(tenantId)) { return await _connectionStringResolver.ResolveAsync(ConnectionStringNameAttribute.GetConnStringName()); } } } /// /// MongoDB数据库API包装类 /// public class MongoDbDatabaseApi : IDatabaseApi { public IAbpMongoDbContext DbContext { get; } public MongoDbDatabaseApi(IAbpMongoDbContext dbContext) { DbContext = dbContext; } } }