mirror of https://github.com/abpframework/abp.git
6 changed files with 163 additions and 21 deletions
@ -0,0 +1,25 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
|
||||
|
namespace Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
public abstract class CachedServiceProviderBase |
||||
|
{ |
||||
|
private readonly IServiceProvider _serviceProvider; |
||||
|
private readonly ConcurrentDictionary<Type, Lazy<object>> _cachedServices; |
||||
|
|
||||
|
protected CachedServiceProviderBase(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
_serviceProvider = serviceProvider; |
||||
|
_cachedServices = new ConcurrentDictionary<Type, Lazy<object>>(); |
||||
|
_cachedServices.TryAdd(typeof(IServiceProvider), new Lazy<object>(() => this)); |
||||
|
} |
||||
|
|
||||
|
public object GetService(Type serviceType) |
||||
|
{ |
||||
|
return _cachedServices.GetOrAdd( |
||||
|
serviceType, |
||||
|
_ => new Lazy<object>(() => _serviceProvider.GetService(serviceType)) |
||||
|
).Value; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides services by caching the resolved services.
|
||||
|
/// It caches all type of services including transients.
|
||||
|
/// This service's lifetime is transient.
|
||||
|
/// <see cref="ICachedServiceProvider"/> for the one with scoped lifetime.
|
||||
|
/// </summary>
|
||||
|
public interface ITransientCachedServiceProvider : IServiceProvider |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
[ExposeServices(typeof(ITransientCachedServiceProvider))] |
||||
|
public class TransientCachedServiceProvider : |
||||
|
CachedServiceProviderBase, |
||||
|
ITransientCachedServiceProvider, |
||||
|
ITransientDependency |
||||
|
{ |
||||
|
public TransientCachedServiceProvider(IServiceProvider serviceProvider) |
||||
|
: base(serviceProvider) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,102 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Testing.Utils; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
public class CachedServiceProvider_Tests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void CachedServiceProvider_Should_Cache_Services() |
||||
|
{ |
||||
|
void TestResolvingServices(IServiceScope scope) |
||||
|
{ |
||||
|
var cachedServiceProvider1 = scope.ServiceProvider.GetRequiredService<ICachedServiceProvider>(); |
||||
|
var cachedServiceProvider2 = scope.ServiceProvider.GetRequiredService<ICachedServiceProvider>(); |
||||
|
cachedServiceProvider1.ShouldBeSameAs(cachedServiceProvider2); |
||||
|
|
||||
|
var transientTestService1 = cachedServiceProvider1.GetRequiredService<TransientTestService>(); |
||||
|
var transientTestService2 = cachedServiceProvider2.GetRequiredService<TransientTestService>(); |
||||
|
transientTestService1.ShouldBeSameAs(transientTestService2); |
||||
|
} |
||||
|
|
||||
|
using (var application = AbpApplicationFactory.Create<TestModule>()) |
||||
|
{ |
||||
|
application.Initialize(); |
||||
|
|
||||
|
using (var scope1 = application.ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
TestResolvingServices(scope1); |
||||
|
var testCounter = scope1.ServiceProvider.GetRequiredService<ITestCounter>(); |
||||
|
testCounter.GetValue(nameof(TransientTestService)).ShouldBe(1); |
||||
|
} |
||||
|
|
||||
|
using (var scope2 = application.ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
TestResolvingServices(scope2); |
||||
|
var testCounter = scope2.ServiceProvider.GetRequiredService<ITestCounter>(); |
||||
|
|
||||
|
//Resolved in a different scope, so should not cache the service!
|
||||
|
testCounter.GetValue(nameof(TransientTestService)).ShouldBe(2); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void TransientCachedServiceProvider_Should_Cache_Services() |
||||
|
{ |
||||
|
void TestResolvingServices(IServiceScope scope) |
||||
|
{ |
||||
|
var cachedServiceProvider1 = scope.ServiceProvider.GetRequiredService<ITransientCachedServiceProvider>(); |
||||
|
|
||||
|
var transientTestService1_1 = cachedServiceProvider1.GetRequiredService<TransientTestService>(); |
||||
|
var transientTestService1_2 = cachedServiceProvider1.GetRequiredService<TransientTestService>(); |
||||
|
transientTestService1_1.ShouldBeSameAs(transientTestService1_2); |
||||
|
|
||||
|
var cachedServiceProvider2 = scope.ServiceProvider.GetRequiredService<ITransientCachedServiceProvider>(); |
||||
|
cachedServiceProvider1.ShouldNotBeSameAs(cachedServiceProvider2); |
||||
|
|
||||
|
var transientTestService2_1 = cachedServiceProvider2.GetRequiredService<TransientTestService>(); |
||||
|
var transientTestService2_2 = cachedServiceProvider2.GetRequiredService<TransientTestService>(); |
||||
|
transientTestService2_1.ShouldBeSameAs(transientTestService2_2); |
||||
|
|
||||
|
transientTestService1_1.ShouldNotBeSameAs(transientTestService2_1); |
||||
|
} |
||||
|
|
||||
|
using (var application = AbpApplicationFactory.Create<TestModule>()) |
||||
|
{ |
||||
|
application.Initialize(); |
||||
|
|
||||
|
using (var scope1 = application.ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
TestResolvingServices(scope1); |
||||
|
var testCounter = scope1.ServiceProvider.GetRequiredService<ITestCounter>(); |
||||
|
testCounter.GetValue(nameof(TransientTestService)).ShouldBe(2); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[DependsOn(typeof(AbpTestBaseModule))] |
||||
|
private class TestModule : AbpModule |
||||
|
{ |
||||
|
public TestModule() |
||||
|
{ |
||||
|
SkipAutoServiceRegistration = true; |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddType<TransientTestService>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private class TransientTestService : ITransientDependency |
||||
|
{ |
||||
|
public TransientTestService(ITestCounter counter) |
||||
|
{ |
||||
|
counter.Increment(nameof(TransientTestService)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue