NetCore 依赖注入之服务之间的依赖关系
简单介绍,直接官方文档
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2
public interface IOperation { Guid OperationId { get; } } public interface IOperationTransient : IOperation { } public interface IOperationScoped : IOperation { } public interface IOperationSingleton : IOperation { } public interface IOperationSingletonInstance : IOperation { }
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance { public Operation() : this(Guid.NewGuid()) { } public Operation(Guid id) { OperationId = id; } public Guid OperationId { get; private set; } }
public class OperationService { public OperationService( IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationSingletonInstance instanceOperation) { TransientOperation = transientOperation; ScopedOperation = scopedOperation; SingletonOperation = singletonOperation; SingletonInstanceOperation = instanceOperation; } public IOperationTransient TransientOperation { get; } public IOperationScoped ScopedOperation { get; } public IOperationSingleton SingletonOperation { get; } public IOperationSingletonInstance SingletonInstanceOperation { get; } }
在 Startup.ConfigureServices 中,根据其指定的生存期,将每个类型添加到容器中: C# public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddScoped<IMyDependency, MyDependency>(); services.AddTransient<IOperationTransient, Operation>(); services.AddScoped<IOperationScoped, Operation>(); services.AddSingleton<IOperationSingleton, Operation>(); services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty)); // OperationService depends on each of the other Operation types. services.AddTransient<OperationService, OperationService>(); }
public class IndexModel : PageModel { private readonly IMyDependency _myDependency; public IndexModel( IMyDependency myDependency, OperationService operationService, IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationSingletonInstance singletonInstanceOperation) { _myDependency = myDependency; OperationService = operationService; TransientOperation = transientOperation; ScopedOperation = scopedOperation; SingletonOperation = singletonOperation; SingletonInstanceOperation = singletonInstanceOperation; } public OperationService OperationService { get; } public IOperationTransient TransientOperation { get; } public IOperationScoped ScopedOperation { get; } public IOperationSingleton SingletonOperation { get; } public IOperationSingletonInstance SingletonInstanceOperation { get; } public async Task OnGetAsync() { await _myDependency.WriteMessage( "IndexModel.OnGetAsync created this message."); } }
以下两个输出显示了两个请求的结果:
第一个请求:
控制器操作:
暂时性:d233e165-f417-469b-a866-1cf1935d2518
作用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19
单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9
实例:00000000-0000-0000-0000-000000000000
OperationService
操作:
暂时性:c6b049eb-1318-4e31-90f1-eb2dd849ff64
作用域:5d997e2d-55f5-4a64-8388-51c4e3a1ad19
单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9
实例:00000000-0000-0000-0000-000000000000
第二个请求:
控制器操作:
暂时性:b63bd538-0a37-4ff1-90ba-081c5138dda0
作用域:31e820c5-4834-4d22-83fc-a60118acb9f4
单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9
实例:00000000-0000-0000-0000-000000000000
OperationService
操作:
暂时性:c4cbacb8-36a2-436d-81c8-8c1b78808aaf
作用域:31e820c5-4834-4d22-83fc-a60118acb9f4
单一实例:01271bc1-9e31-48e7-8f7c-7261b040ded9
实例:00000000-0000-0000-0000-000000000000
观察哪个 OperationId
值会在一个请求之内和不同请求之间变化:
- 暂时性 对象始终不同。 第一个和第二个客户端请求的暂时性
OperationId
值对于OperationService
操作和在客户端请求内都是不同的。 为每个服务请求和客户端请求提供了一个新实例。 - 作用域 对象在一个客户端请求中是相同的,但在多个客户端请求中是不同的。
- 单一实例 对象对每个对象和每个请求都是相同的(不管
Startup.ConfigureServices
中是否提供Operation
实例)。
接下来是本文重点要说明的
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<SingletonService>(); services.AddTransient<TransientService>(); services.AddScoped<ScopedService>(); }
public class SingletonService { public string Id = Guid.NewGuid().ToString(); } public class ScopedService { public string Id = Guid.NewGuid().ToString(); } public class TransientService { public string Id = Guid.NewGuid().ToString(); private ScopedService _transient; private SingletonService _singleton; public TransientService(ScopedService transient, SingletonService singleton) { _transient = transient; _singleton = singleton; } }
这种情况是可以的,transient 可以依赖 singleton 和 scoped
对于 Transient 服务,它可以被任何服务依赖,但是在依赖的服务中创建的服务的生命周期会跟随依赖的服务
对于 Scoped 服务,它只能被 Transient 和 Scoped 服务依赖,生命周期不会变化,如果要在 Singleton 服务中使用,可以使用 IServiceProvider 的 CreateScope 方法 ,然后 GetService, 但是 生成的 scoped 服务生命周期为 Singleton
对于 Singleton 服务,它可以被任何服务依赖,生命周期不会变化
public class SingletonService { public string Id = Guid.NewGuid().ToString(); private ScopedService _scoped; public SingletonService(IServiceProvider serviceProvider) { using (var scope = serviceProvider.CreateScope()) { _scoped = scope.ServiceProvider.GetService<ScopedService>(); } } } public class ScopedService { public string Id = Guid.NewGuid().ToString(); } public class TransientService { public string Id = Guid.NewGuid().ToString(); }
这个 在单例中使用 Scoped 服务