Browse Source

Merge pull request #14880 from abpframework/auto-merge/rel-7-0/1510

Merge branch dev with rel-7.0
pull/14894/head
maliming 4 years ago
committed by GitHub
parent
commit
79007e7deb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      docs/en/Dependency-Injection.md
  2. 25
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs
  3. 1
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProvider.cs
  4. 25
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs
  5. 40
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IAbpLazyServiceProvider.cs
  6. 6
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ICachedServiceProvider.cs
  7. 14
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ICachedServiceProviderBase.cs
  8. 4
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ITransientCachedServiceProvider.cs

35
docs/en/Dependency-Injection.md

@ -403,6 +403,41 @@ using (var scope = _serviceProvider.CreateScope())
Both services are released when the created scope is disposed (at the end of the `using` block). Both services are released when the created scope is disposed (at the end of the `using` block).
### Cached Service Providers
ABP provides two special services to optimize resolving services from `IServiceProvider`. `ICachedServiceProvider` and `ITransientCachedServiceProvider` both inherits from the `IServiceProvider` interface and internally caches the resolved services, so you get the same service instance even if you resolve a service multiple times.
The main difference is the `ICachedServiceProvider` is itself registered as scoped, while the `ITransientCachedServiceProvider` is registered as transient to the dependency injection system.
The following example injects the `ICachedServiceProvider` service and resolves a service in the `DoSomethingAsync` method:
````csharp
public class MyService : ITransientDependency
{
private readonly ICachedServiceProvider _serviceProvider;
public MyService(ICachedServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task DoSomethingAsync()
{
var taxCalculator = _serviceProvider.GetRequiredService<ITaxCalculator>();
// TODO: Use the taxCalculator
}
}
````
With such a usage, you don't need to deal with creating service scopes and disposing the resolved services (as explained in the *Releasing/Disposing Services* section above). Because all the services resolved from the `ICachedServiceProvider` will be released once the service scope of the `MyService` instance is disposed. Also, you don't need to care about memory leaks (because of creating too many `ITaxCalculator` instances if we call `DoSomethingAsync` too many times), because only one `ITaxCalculator` instance is created, and it is reused.
Since `ICachedServiceProvider` and `ITransientCachedServiceProvider` extends the standard `IServiceProvider` interface, you can use all the extension method of the `IServiceProvider` interface on them. In addition, they provides some other methods to provide a default value or a factory method for the services that are not found (that means not registered to the dependency injection system). Notice that the default value (or the value returned from your factory method) is also cached and reused.
Use `ICachedServiceProvider` (instead of `ITransientCachedServiceProvider`) unless you need to create the service cache per usage. `ITransientCachedServiceProvider` guarantees that the created service instances are not shared with any other service, even they are in the same service scope. The services resolved from `ICachedServiceProvider` are shared with other services in the same service scope (in the same HTTP Request, for example), so it can be thought as more optimized.
> ABP Framework also provides the `IAbpLazyServiceProvider` service. It does exists for backward compatibility and works exactly same with the `ITransientCachedServiceProvider` service. So, use the `ITransientCachedServiceProvider` since the `IAbpLazyServiceProvider` might be removed in future ABP versions.
## Advanced Features ## Advanced Features
### IServiceCollection.OnRegistred Event ### IServiceCollection.OnRegistred Event

25
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs

@ -1,15 +1,23 @@
using System; using System;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.DependencyInjection; namespace Volo.Abp.DependencyInjection;
/// <summary>
/// This class is equivalent of the <see cref="TransientCachedServiceProvider"/>.
/// Use <see cref="TransientCachedServiceProvider"/> instead of this class, for new projects.
/// </summary>
[ExposeServices(typeof(IAbpLazyServiceProvider))] [ExposeServices(typeof(IAbpLazyServiceProvider))]
public class AbpLazyServiceProvider : CachedServiceProviderBase, IAbpLazyServiceProvider, ITransientDependency public class AbpLazyServiceProvider :
CachedServiceProviderBase,
IAbpLazyServiceProvider,
ITransientDependency
{ {
public AbpLazyServiceProvider(IServiceProvider serviceProvider) public AbpLazyServiceProvider(IServiceProvider serviceProvider)
: base(serviceProvider) : base(serviceProvider)
{ {
} }
public virtual T LazyGetRequiredService<T>() public virtual T LazyGetRequiredService<T>()
{ {
return (T)LazyGetRequiredService(typeof(T)); return (T)LazyGetRequiredService(typeof(T));
@ -17,7 +25,7 @@ public class AbpLazyServiceProvider : CachedServiceProviderBase, IAbpLazyService
public virtual object LazyGetRequiredService(Type serviceType) public virtual object LazyGetRequiredService(Type serviceType)
{ {
return GetService(serviceType); return this.GetRequiredService(serviceType);
} }
public virtual T LazyGetService<T>() public virtual T LazyGetService<T>()
@ -32,24 +40,21 @@ public class AbpLazyServiceProvider : CachedServiceProviderBase, IAbpLazyService
public virtual T LazyGetService<T>(T defaultValue) public virtual T LazyGetService<T>(T defaultValue)
{ {
return (T)LazyGetService(typeof(T), defaultValue); return GetService(defaultValue);
} }
public virtual object LazyGetService(Type serviceType, object defaultValue) public virtual object LazyGetService(Type serviceType, object defaultValue)
{ {
return LazyGetService(serviceType) ?? defaultValue; return GetService(serviceType, defaultValue);
} }
public virtual T LazyGetService<T>(Func<IServiceProvider, object> factory) public virtual T LazyGetService<T>(Func<IServiceProvider, object> factory)
{ {
return (T)LazyGetService(typeof(T), factory); return GetService<T>(factory);
} }
public virtual object LazyGetService(Type serviceType, Func<IServiceProvider, object> factory) public virtual object LazyGetService(Type serviceType, Func<IServiceProvider, object> factory)
{ {
return CachedServices.GetOrAdd( return GetService(serviceType, factory);
serviceType,
_ => new Lazy<object>(() => factory(ServiceProvider))
).Value;
} }
} }

1
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProvider.cs

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
namespace Volo.Abp.DependencyInjection; namespace Volo.Abp.DependencyInjection;

25
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs

@ -3,7 +3,7 @@ using System.Collections.Concurrent;
namespace Volo.Abp.DependencyInjection; namespace Volo.Abp.DependencyInjection;
public abstract class CachedServiceProviderBase public abstract class CachedServiceProviderBase : ICachedServiceProviderBase
{ {
protected IServiceProvider ServiceProvider { get; } protected IServiceProvider ServiceProvider { get; }
protected ConcurrentDictionary<Type, Lazy<object>> CachedServices { get; } protected ConcurrentDictionary<Type, Lazy<object>> CachedServices { get; }
@ -22,4 +22,27 @@ public abstract class CachedServiceProviderBase
_ => new Lazy<object>(() => ServiceProvider.GetService(serviceType)) _ => new Lazy<object>(() => ServiceProvider.GetService(serviceType))
).Value; ).Value;
} }
public T GetService<T>(T defaultValue)
{
return (T)GetService(typeof(T), defaultValue);
}
public object GetService(Type serviceType, object defaultValue)
{
return GetService(serviceType) ?? defaultValue;
}
public T GetService<T>(Func<IServiceProvider, object> factory)
{
return (T)GetService(typeof(T), factory);
}
public object GetService(Type serviceType, Func<IServiceProvider, object> factory)
{
return CachedServices.GetOrAdd(
serviceType,
_ => new Lazy<object>(() => factory(ServiceProvider))
).Value;
}
} }

40
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IAbpLazyServiceProvider.cs

@ -2,21 +2,57 @@
namespace Volo.Abp.DependencyInjection; namespace Volo.Abp.DependencyInjection;
public interface IAbpLazyServiceProvider /// <summary>
/// This service is equivalent of the <see cref="ITransientCachedServiceProvider"/>.
/// Use <see cref="ITransientCachedServiceProvider"/> instead of this interface, for new projects.
/// </summary>
public interface IAbpLazyServiceProvider : ICachedServiceProviderBase
{ {
/// <summary>
/// This method is equivalent of the GetRequiredService method.
/// It does exists for backward compatibility.
/// </summary>
T LazyGetRequiredService<T>(); T LazyGetRequiredService<T>();
/// <summary>
/// This method is equivalent of the GetRequiredService method.
/// It does exists for backward compatibility.
/// </summary>
object LazyGetRequiredService(Type serviceType); object LazyGetRequiredService(Type serviceType);
/// <summary>
/// This method is equivalent of the GetService method.
/// It does exists for backward compatibility.
/// </summary>
T LazyGetService<T>(); T LazyGetService<T>();
/// <summary>
/// This method is equivalent of the GetService method.
/// It does exists for backward compatibility.
/// </summary>
object LazyGetService(Type serviceType); object LazyGetService(Type serviceType);
/// <summary>
/// This method is equivalent of the <see cref="ICachedServiceProviderBase.GetService{T}(T)"/> method.
/// It does exists for backward compatibility.
/// </summary>
T LazyGetService<T>(T defaultValue); T LazyGetService<T>(T defaultValue);
/// <summary>
/// This method is equivalent of the <see cref="ICachedServiceProviderBase.GetService(Type, object)"/> method.
/// It does exists for backward compatibility.
/// </summary>
object LazyGetService(Type serviceType, object defaultValue); object LazyGetService(Type serviceType, object defaultValue);
/// <summary>
/// This method is equivalent of the <see cref="ICachedServiceProviderBase.GetService(Type, Func{IServiceProvider, object})"/> method.
/// It does exists for backward compatibility.
/// </summary>
object LazyGetService(Type serviceType, Func<IServiceProvider, object> factory); object LazyGetService(Type serviceType, Func<IServiceProvider, object> factory);
/// <summary>
/// This method is equivalent of the <see cref="ICachedServiceProviderBase.GetService{T}(Func{IServiceProvider, object})"/> method.
/// It does exists for backward compatibility.
/// </summary>
T LazyGetService<T>(Func<IServiceProvider, object> factory); T LazyGetService<T>(Func<IServiceProvider, object> factory);
} }

6
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ICachedServiceProvider.cs

@ -1,6 +1,4 @@
using System; namespace Volo.Abp.DependencyInjection;
namespace Volo.Abp.DependencyInjection;
/// <summary> /// <summary>
/// Provides services by caching the resolved services. /// Provides services by caching the resolved services.
@ -8,7 +6,7 @@ namespace Volo.Abp.DependencyInjection;
/// This service's lifetime is scoped and it should be used /// This service's lifetime is scoped and it should be used
/// for a limited scope. /// for a limited scope.
/// </summary> /// </summary>
public interface ICachedServiceProvider : IServiceProvider public interface ICachedServiceProvider : ICachedServiceProviderBase
{ {
} }

14
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ICachedServiceProviderBase.cs

@ -0,0 +1,14 @@
using System;
namespace Volo.Abp.DependencyInjection;
public interface ICachedServiceProviderBase : IServiceProvider
{
T GetService<T>(T defaultValue);
object GetService(Type serviceType, object defaultValue);
T GetService<T>(Func<IServiceProvider, object> factory);
object GetService(Type serviceType, Func<IServiceProvider, object> factory);
}

4
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ITransientCachedServiceProvider.cs

@ -1,5 +1,3 @@
using System;
namespace Volo.Abp.DependencyInjection; namespace Volo.Abp.DependencyInjection;
/// <summary> /// <summary>
@ -8,7 +6,7 @@ namespace Volo.Abp.DependencyInjection;
/// This service's lifetime is transient. /// This service's lifetime is transient.
/// <see cref="ICachedServiceProvider"/> for the one with scoped lifetime. /// <see cref="ICachedServiceProvider"/> for the one with scoped lifetime.
/// </summary> /// </summary>
public interface ITransientCachedServiceProvider : IServiceProvider public interface ITransientCachedServiceProvider : ICachedServiceProviderBase
{ {
} }
Loading…
Cancel
Save