From d3c613d121092cfeba195837069d9c04b3e4acfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 16 Dec 2016 22:54:13 +0300 Subject: [PATCH] Creates basic UOW classes and revised codebase. --- .../AbpEfCoreServiceCollectionExtensions.cs | 35 +------------- .../DbContextOptionsFactory.cs | 44 +++++++++++++++++ .../AbpEntityFrameworkCoreModule.cs | 2 +- .../DefaultDbContextProvider.cs | 20 -------- .../UnitOfWorkDbContextProvider.cs | 31 ++++++++++++ .../AsyncLocalTenantScopeProvider.cs | 8 ++-- src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs | 32 +++++++++++++ src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs | 13 +++++ .../Volo/Abp/Uow/IUnitOfWorkManager.cs | 9 ++++ src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs | 23 +++++++++ src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInfo.cs | 17 +++++++ .../Volo/Abp/Uow/UnitOfWorkManager.cs | 48 +++++++++++++++++++ .../AbpDependencyInjectionSpecifications.cs | 19 ++++++++ 13 files changed, 243 insertions(+), 58 deletions(-) create mode 100644 src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/DbContextOptionsFactory.cs delete mode 100644 src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/DefaultDbContextProvider.cs create mode 100644 src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs create mode 100644 src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs create mode 100644 src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs create mode 100644 src/Volo.Abp/Volo/Abp/Uow/IUnitOfWorkManager.cs create mode 100644 src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs create mode 100644 src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInfo.cs create mode 100644 src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs create mode 100644 test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs diff --git a/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs b/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs index b75694ccea..d74d5a77db 100644 --- a/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs +++ b/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs @@ -1,14 +1,8 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; -using Volo.Abp; -using Volo.Abp.Data; +using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Repositories.EntityFrameworkCore; -using Volo.ExtensionMethods.Collections.Generic; namespace Microsoft.Extensions.DependencyInjection { @@ -23,32 +17,7 @@ namespace Microsoft.Extensions.DependencyInjection .AddLogging(); services.TryAddTransient(); - services.TryAddSingleton(serviceProvider => - { - const string moduleName = ""; //TODO: Use AbpModuleDescriptor instead of module name? - - var connInfoResolver = serviceProvider.GetRequiredService(); - - var context = new AbpDbContextConfigurationContext(connInfoResolver.Resolve(moduleName), moduleName); - - var dbContextOptions = serviceProvider.GetRequiredService>().Value; - - var configureAction = dbContextOptions.ConfigureActions.GetOrDefault(typeof(TDbContext)); - if (configureAction != null) - { - ((Action>) configureAction).Invoke(context); - } - else if(dbContextOptions.DefaultConfigureAction != null) - { - dbContextOptions.DefaultConfigureAction.Invoke(context); - } - else - { - throw new AbpException("Should set a configure action for dbcontext"); //TODO: Better message - } - - return context.DbContextOptions.Options; - }); + services.TryAddSingleton(DbContextOptionsFactory.Create); return services; } diff --git a/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/DbContextOptionsFactory.cs b/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/DbContextOptionsFactory.cs new file mode 100644 index 0000000000..6f46988f62 --- /dev/null +++ b/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/DbContextOptionsFactory.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; +using Volo.ExtensionMethods.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection +{ + internal static class DbContextOptionsFactory + { + public static DbContextOptions Create(IServiceProvider serviceProvider) + where TDbContext : AbpDbContext + { + const string moduleName = ""; //TODO: Use AbpModuleDescriptor instead of module name? + + using (var scope = serviceProvider.CreateScope()) + { + var connInfoResolver = scope.ServiceProvider.GetRequiredService(); + + var context = new AbpDbContextConfigurationContext(connInfoResolver.Resolve(moduleName), moduleName); + + var dbContextOptions = scope.ServiceProvider.GetRequiredService>().Value; + + var configureAction = dbContextOptions.ConfigureActions.GetOrDefault(typeof(TDbContext)); + if (configureAction != null) + { + ((Action>)configureAction).Invoke(context); + } + else if (dbContextOptions.DefaultConfigureAction != null) + { + dbContextOptions.DefaultConfigureAction.Invoke(context); + } + else + { + throw new AbpException("Should set a configure action for dbcontext"); //TODO: Better message + } + + return context.DbContextOptions.Options; + } + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs index 437a3204a6..1411daa38e 100644 --- a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs +++ b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.EntityFrameworkCore public override void ConfigureServices(IServiceCollection services) { //TODO: This will be changed! - services.TryAddTransient(typeof(IDbContextProvider<>), typeof(DefaultDbContextProvider<>)); + services.TryAddTransient(typeof(IDbContextProvider<>), typeof(UnitOfWorkDbContextProvider<>)); } } } diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/DefaultDbContextProvider.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/DefaultDbContextProvider.cs deleted file mode 100644 index c06f975b69..0000000000 --- a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/DefaultDbContextProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Volo.Abp.EntityFrameworkCore; - -namespace Volo.Abp.Repositories.EntityFrameworkCore -{ - public class DefaultDbContextProvider : IDbContextProvider - where TDbContext : AbpDbContext - { - private readonly TDbContext _dbContext; - - public DefaultDbContextProvider(TDbContext dbContext) //TODO: Should create this dynamically! - { - _dbContext = dbContext; - } - - public TDbContext GetDbContext() - { - return _dbContext; - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs new file mode 100644 index 0000000000..b27c5b6526 --- /dev/null +++ b/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Repositories/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -0,0 +1,31 @@ +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Uow; + +namespace Volo.Abp.Repositories.EntityFrameworkCore +{ + public class UnitOfWorkDbContextProvider : IDbContextProvider + where TDbContext : AbpDbContext + { + private readonly TDbContext _dbContext; + + private readonly IUnitOfWorkManager _unitOfWorkManager; + + public UnitOfWorkDbContextProvider( + TDbContext dbContext, + IUnitOfWorkManager unitOfWorkManager) //TODO: Should create this dynamically inside a unit of work. + { + _dbContext = dbContext; + _unitOfWorkManager = unitOfWorkManager; + } + + public TDbContext GetDbContext() + { + //if (_unitOfWorkManager.Current == null) + //{ + // throw new AbpException("A DbContext can only be created inside a unit of work!"); + //} + + return _dbContext; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AsyncLocalTenantScopeProvider.cs b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AsyncLocalTenantScopeProvider.cs index fb70cdf378..dcc0a6f507 100644 --- a/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AsyncLocalTenantScopeProvider.cs +++ b/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/AsyncLocalTenantScopeProvider.cs @@ -8,15 +8,15 @@ namespace Volo.Abp.MultiTenancy { public TenantScope CurrentScope { - get { return _tenant.Value; } - private set { _tenant.Value = value; } + get { return _currentScope.Value; } + private set { _currentScope.Value = value; } } - private readonly AsyncLocal _tenant; + private readonly AsyncLocal _currentScope; public AsyncLocalTenantScopeProvider() { - _tenant = new AsyncLocal(); + _currentScope = new AsyncLocal(); } public IDisposable EnterScope(TenantInfo tenantInfo) diff --git a/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs new file mode 100644 index 0000000000..acc898710a --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using JetBrains.Annotations; + +namespace Volo.Abp.Uow +{ + internal class ChildUnitOfWork : IUnitOfWork + { + private readonly IUnitOfWork _parent; + + public ChildUnitOfWork([NotNull] IUnitOfWork parent) + { + Check.NotNull(parent, nameof(parent)); + + _parent = parent; + } + + public Task SaveChangesAsync() + { + return _parent.SaveChangesAsync(); + } + + public Task CompleteAsync() + { + return Task.CompletedTask; + } + + public void Dispose() + { + + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs new file mode 100644 index 0000000000..935f674e2c --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using Volo.DependencyInjection; + +namespace Volo.Abp.Uow +{ + public interface IUnitOfWork : IDisposable, ITransientDependency + { + Task SaveChangesAsync(); + + Task CompleteAsync(); + } +} diff --git a/src/Volo.Abp/Volo/Abp/Uow/IUnitOfWorkManager.cs b/src/Volo.Abp/Volo/Abp/Uow/IUnitOfWorkManager.cs new file mode 100644 index 0000000000..6ec2d6911f --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Uow/IUnitOfWorkManager.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.Uow +{ + public interface IUnitOfWorkManager + { + IUnitOfWork Current { get; } + + IUnitOfWork Begin(); + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs new file mode 100644 index 0000000000..5a1377b520 --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading.Tasks; + +namespace Volo.Abp.Uow +{ + public class UnitOfWork : IUnitOfWork + { + public void Dispose() + { + throw new NotImplementedException(); + } + + public Task SaveChangesAsync() + { + throw new NotImplementedException(); + } + + public Task CompleteAsync() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInfo.cs b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInfo.cs new file mode 100644 index 0000000000..c34465bc63 --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInfo.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Volo.Abp.Uow +{ + internal class UnitOfWorkInfo + { + public IUnitOfWork UnitOfWork { get; set; } + + public IServiceScope ServiceScope { get; set; } + + public UnitOfWorkInfo(IUnitOfWork unitOfWork, IServiceScope serviceScope) + { + UnitOfWork = unitOfWork; + ServiceScope = serviceScope; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs new file mode 100644 index 0000000000..82d6755512 --- /dev/null +++ b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading; +using Microsoft.Extensions.DependencyInjection; +using Volo.DependencyInjection; + +namespace Volo.Abp.Uow +{ + public class UnitOfWorkManager : IUnitOfWorkManager, ISingletonDependency + { + //TODO: Skipped many feature of Abp 1.x + + public IUnitOfWork Current => _currentUowInfo.Value?.UnitOfWork; + + private readonly AsyncLocal _currentUowInfo; + private readonly IServiceProvider _serviceProvider; + + public UnitOfWorkManager(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _currentUowInfo = new AsyncLocal(); + } + + public IUnitOfWork Begin() + { + if (Current != null) + { + return new ChildUnitOfWork(Current); + } + + var scope = _serviceProvider.CreateScope(); + + try + { + _currentUowInfo.Value = new UnitOfWorkInfo( + scope.ServiceProvider.GetRequiredService(), + scope + ); + } + catch + { + scope.Dispose(); + throw; + } + + return Current; + } + } +} \ No newline at end of file diff --git a/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs b/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs new file mode 100644 index 0000000000..7ea2bb0f04 --- /dev/null +++ b/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.DependencyInjection; + +namespace Microsoft.Extensions.DependencyInjection +{ + public class AbpDependencyInjectionSpecifications + { + //TODO: Tests... + + public class MyScopedClass : IScopedDependency + { + + } + + } +}