From 4b595a1427c47542eb8da41b876db718b0bbc554 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 28 Dec 2020 15:21:25 +0800 Subject: [PATCH] Use IAbpLazyServiceProvider instead of property injection. --- .../AbpLazyServiceProvider.cs | 60 +++++++++++++++++++ .../IAbpLazyServiceProvider.cs | 23 +++++++ .../Repositories/BasicRepositoryBase.cs | 14 +++-- .../EntityFrameworkCore/EfCoreRepository.cs | 44 +++++++------- .../Abp/EntityFrameworkCore/AbpDbContext.cs | 28 ++++----- 5 files changed, 125 insertions(+), 44 deletions(-) create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IAbpLazyServiceProvider.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs new file mode 100644 index 0000000000..b085b90722 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; + +namespace Volo.Abp.DependencyInjection +{ + public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDependency + { + protected IDictionary> CachedTypes { get; set; } + + protected IServiceProvider ServiceProvider { get; set; } + + public AbpLazyServiceProvider(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + + CachedTypes = new Dictionary>(); + } + + public virtual T LazyGetRequiredService() + { + return (T)CachedTypes.GetOrAdd(typeof(T), () => new Lazy(() => (T) ServiceProvider.GetRequiredService(typeof(T)))).Value; + } + + public virtual object LazyGetRequiredService(Type serviceType) + { + return CachedTypes.GetOrAdd(serviceType, () => new Lazy(() => ServiceProvider.GetRequiredService(serviceType))).Value; + } + + public virtual T LazyGetService() + { + return (T)CachedTypes.GetOrAdd(typeof(T), () => new Lazy(() => (T) ServiceProvider.GetService(typeof(T)))).Value; + } + + public virtual object LazyGetService(Type serviceType) + { + return CachedTypes.GetOrAdd(serviceType, () => new Lazy(() => ServiceProvider.GetService(serviceType))).Value; + } + + public virtual T LazyGetService(T defaultValue) + { + return LazyGetService() ?? defaultValue; + } + + public virtual object LazyGetService(Type serviceType, object defaultValue) + { + return LazyGetService(serviceType) ?? defaultValue; + } + + public virtual object LazyGetService(Type serviceType, Func factory) + { + return CachedTypes.GetOrAdd(serviceType, () => new Lazy(() => factory(ServiceProvider))).Value; + } + + public virtual T LazyGetService(Func factory) + { + return (T)CachedTypes.GetOrAdd(typeof(T), () => new Lazy(() => factory(ServiceProvider))).Value; + } + } +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IAbpLazyServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IAbpLazyServiceProvider.cs new file mode 100644 index 0000000000..cea6c05ebf --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IAbpLazyServiceProvider.cs @@ -0,0 +1,23 @@ +using System; + +namespace Volo.Abp.DependencyInjection +{ + public interface IAbpLazyServiceProvider + { + T LazyGetRequiredService(); + + object LazyGetRequiredService(Type serviceType); + + T LazyGetService(); + + object LazyGetService(Type serviceType); + + T LazyGetService(T defaultValue); + + object LazyGetService(Type serviceType, object defaultValue); + + object LazyGetService(Type serviceType, Func factory); + + T LazyGetService(Func factory); + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs index 8bcf98dff1..65c2cc897b 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs @@ -19,21 +19,23 @@ namespace Volo.Abp.Domain.Repositories IUnitOfWorkEnabled where TEntity : class, IEntity { + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + public IServiceProvider ServiceProvider { get; set; } - public IDataFilter DataFilter { get; set; } + public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService(); - public ICurrentTenant CurrentTenant { get; set; } + public ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService(); - public IAsyncQueryableExecuter AsyncExecuter { get; set; } + public IAsyncQueryableExecuter AsyncExecuter => LazyServiceProvider.LazyGetRequiredService(); - public IUnitOfWorkManager UnitOfWorkManager { get; set; } + public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService(); - public ICancellationTokenProvider CancellationTokenProvider { get; set; } + public ICancellationTokenProvider CancellationTokenProvider => LazyServiceProvider.LazyGetService(NullCancellationTokenProvider.Instance); protected BasicRepositoryBase() { - CancellationTokenProvider = NullCancellationTokenProvider.Instance; + } public abstract Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index ca885bd4fb..2e1d79f2f9 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -2,7 +2,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Nito.AsyncEx; using System; using System.Collections.Generic; using System.Linq; @@ -32,14 +31,13 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore private readonly IDbContextProvider _dbContextProvider; private readonly Lazy> _entityOptionsLazy; - public virtual IGuidGenerator GuidGenerator { get; set; } + public virtual IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetService(SimpleGuidGenerator.Instance); - public IEfCoreBulkOperationProvider BulkOperationProvider { get; set; } + public IEfCoreBulkOperationProvider BulkOperationProvider => LazyServiceProvider.LazyGetRequiredService(); public EfCoreRepository(IDbContextProvider dbContextProvider) { _dbContextProvider = dbContextProvider; - GuidGenerator = SimpleGuidGenerator.Instance; _entityOptionsLazy = new Lazy>( () => ServiceProvider @@ -49,15 +47,15 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore ); } - public async override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { CheckAndSetId(entity); - var savedEntity = DbSet.Add(entity).Entity; + var savedEntity = (await DbSet.AddAsync(entity, GetCancellationToken(cancellationToken))).Entity; if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await DbContext.SaveChangesAsync(GetCancellationToken(GetCancellationToken(cancellationToken))); } return savedEntity; @@ -76,20 +74,20 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore this, entities, autoSave, - cancellationToken + GetCancellationToken(cancellationToken) ); return; } - await DbSet.AddRangeAsync(entities); + await DbSet.AddRangeAsync(entities, GetCancellationToken(cancellationToken)); if (autoSave) { - await DbContext.SaveChangesAsync(); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } } - public async override Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { DbContext.Attach(entity); @@ -111,7 +109,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore this, entities, autoSave, - cancellationToken + GetCancellationToken(cancellationToken) ); return; @@ -121,11 +119,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore if (autoSave) { - await DbContext.SaveChangesAsync(); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } } - public async override Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { DbSet.Remove(entity); @@ -152,23 +150,23 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore if (autoSave) { - await DbContext.SaveChangesAsync(); + await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } } - public async override Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) + public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { return includeDetails ? await WithDetails().ToListAsync(GetCancellationToken(cancellationToken)) : await DbSet.ToListAsync(GetCancellationToken(cancellationToken)); } - public async override Task GetCountAsync(CancellationToken cancellationToken = default) + public override async Task GetCountAsync(CancellationToken cancellationToken = default) { return await DbSet.LongCountAsync(GetCancellationToken(cancellationToken)); } - public async override Task> GetPagedListAsync( + public override async Task> GetPagedListAsync( int skipCount, int maxResultCount, string sorting, @@ -190,10 +188,10 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore protected override Task SaveChangesAsync(CancellationToken cancellationToken) { - return DbContext.SaveChangesAsync(cancellationToken); + return DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } - public async override Task FindAsync( + public override async Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) @@ -207,7 +205,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore .SingleOrDefaultAsync(GetCancellationToken(cancellationToken)); } - public async override Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { var entities = await GetQueryable() .Where(predicate) @@ -344,9 +342,9 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore await DeleteAsync(entity, autoSave, cancellationToken); } - public async virtual Task DeleteManyAsync([NotNull] IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) + public virtual async Task DeleteManyAsync([NotNull] IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = await DbSet.Where(x => ids.Contains(x.Id)).ToListAsync(); + var entities = await DbSet.Where(x => ids.Contains(x.Id)).ToListAsync(GetCancellationToken(cancellationToken)); await DeleteManyAsync(entities, autoSave, cancellationToken); } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index a17aab8621..24ba939e90 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -23,7 +23,6 @@ using Volo.Abp.EntityFrameworkCore.EntityHistory; using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.Guids; -using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectExtending; using Volo.Abp.Reflection; @@ -35,31 +34,33 @@ namespace Volo.Abp.EntityFrameworkCore public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, ITransientDependency where TDbContext : DbContext { + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + protected virtual Guid? CurrentTenantId => CurrentTenant?.Id; protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled() ?? false; protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled() ?? false; - public ICurrentTenant CurrentTenant { get; set; } + public ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService(); - public IGuidGenerator GuidGenerator { get; set; } + public IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetService(SimpleGuidGenerator.Instance); - public IDataFilter DataFilter { get; set; } + public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService(); - public IEntityChangeEventHelper EntityChangeEventHelper { get; set; } + public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService(NullEntityChangeEventHelper.Instance); - public IAuditPropertySetter AuditPropertySetter { get; set; } + public IAuditPropertySetter AuditPropertySetter => LazyServiceProvider.LazyGetRequiredService(); - public IEntityHistoryHelper EntityHistoryHelper { get; set; } + public IEntityHistoryHelper EntityHistoryHelper => LazyServiceProvider.LazyGetService(NullEntityHistoryHelper.Instance); - public IAuditingManager AuditingManager { get; set; } + public IAuditingManager AuditingManager => LazyServiceProvider.LazyGetRequiredService(); - public IUnitOfWorkManager UnitOfWorkManager { get; set; } + public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService(); - public IClock Clock { get; set; } + public IClock Clock => LazyServiceProvider.LazyGetRequiredService(); - public ILogger> Logger { get; set; } + public ILogger> Logger => LazyServiceProvider.LazyGetService>>(NullLogger>.Instance); private static readonly MethodInfo ConfigureBasePropertiesMethodInfo = typeof(AbpDbContext) @@ -85,10 +86,7 @@ namespace Volo.Abp.EntityFrameworkCore protected AbpDbContext(DbContextOptions options) : base(options) { - GuidGenerator = SimpleGuidGenerator.Instance; - EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; - EntityHistoryHelper = NullEntityHistoryHelper.Instance; - Logger = NullLogger>.Instance; + } protected override void OnModelCreating(ModelBuilder modelBuilder)