4. 容器中的服务创建与释放
首先是新增三个类,用于注册三种不同的生命周期:
public class Service1
{
public Service1(
{
Console.WriteLine("Service1 Created";
}
}
public class Service2
{
public Service2(
{
Console.WriteLine("Service2 Created";
}
}
public class Service3
{
public Service3(
{
Console.WriteLine("Service3 Created";
}
}
接下来是演示场景,为了简单起见,就用后台服务程序吧
IHost host = Host.CreateDefaultBuilder(args
.ConfigureServices(services =>
{
services.AddHostedService<Worker>(;
services.AddSingleton<Service1>(;
services.AddScoped<Service2>(;
services.AddTransient<Service3>(;
}
.Build(;
await host.RunAsync(;
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IServiceProvider _serviceProvid
public Worker(ILogger<Worker> logger, IServiceProvider serviceProvider
{
_logger = logger;
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken
{
#region 生命周期实例创建
Console.WriteLine("Service1 第一次调用";
var service11 = _serviceProvider.GetService<Service1>(;
Console.WriteLine("Service1 第二次调用";
var service12 = _serviceProvider.GetService<Service1>(;
// 创建作用域,与 Web 应用中的一次请求一样
using (var scope = _serviceProvider.CreateScope(
{
Console.WriteLine("Service2 第一次调用";
var service31 = scope.ServiceProvider.GetService<Service2>(;
Console.WriteLine("Service2 第二次调用";
var service32 = scope.ServiceProvider.GetService<Service2>(;
using (var scope1 = _serviceProvider.CreateScope(
{
Console.WriteLine("Service2 第三次调用";
var service33 = scope1.ServiceProvider.GetService<Service2>(;
}
}
{
Console.WriteLine("Service3 第一次调用";
var service41 = _serviceProvider.GetService<Service3>(;
Console.WriteLine("Service3 第二次调用";
var service42 = _serviceProvider.GetService<Service3>(;
}
#endregion
}
}
}
最终的输出如下:
看完创建,我们再看实例销毁的时机。
public class Service1 : IDisposable
{
public Service1(
{
Console.WriteLine("Service1 Created";
public void Dispose(
{
Console.WriteLine("Service1 Dispose";
}
}
public class Service2 : IDisposable
{
public Service2(
{
Console.WriteLine("Service2 Created";
public void Dispose(
{
Console.WriteLine("Service2 Dispose";
}
}
public class Service3 : IDisposable
{
public Service3(
{
Console.WriteLine("Service3 Created";
}
public void Dispose(
{
Console.WriteLine("Service3 Dispose";
}
}
public class Service4 : IDisposable
{
public void Dispose(
{
Console.WriteLine("Service4 Dispose";
}
}
public class Service5 : IDisposable
{
public void Dispose(
{
Console.WriteLine("Service5 Dispose";
}
}
之后后台服务程序也做一些修改
IHost host = Host.CreateDefaultBuilder(args
.ConfigureServices(services =>
{
services.AddHostedService<Worker>(;
services.AddSingleton<Service1>(;
services.AddScoped<Service2>(;
services.AddTransient<Service3>(;
// 这种方式依旧由容器创建实例,只不过提供了工厂方法
services.AddSingleton<Service4>(provider => new Service4(;
// 这种方式是用外部创建实例,只有单例生命周期可用
services.AddSingleton<Service5>(new Service5(;
}
.Build(;
await host.RunAsync(;
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IServiceProvider _serviceProvid
public Worker(ILogger<Worker> logger, IServiceProvider serviceProvider
{
_logger = logger;
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken
{
#region 生命周期实
Console.WriteLine("Service1 调用";
var service1 = _serviceProvider.GetService<Service1>(;
// 创建作用域,与 Web 应用中的一次请求一样
using (var scope = _serviceProvider.CreateScope(
{
Console.WriteLine("Service2 调用";
var service2 = scope.ServiceProvider.GetService<Service2>(;
Console.WriteLine("即将结束作用域
Console.WriteLine("Service3 调用";
var service3 = scope.ServiceProvider.GetService<Service3>(;
}
Console.WriteLine("Service4 调用";
var service4 = _serviceProvider.GetService<Service4>(;
Console.WriteLine("Service5 调用";
var service5 = _serviceProvider.GetService<Service5>(;
#endregion
}
}
这样要直接用命令启动应用,不能够通过vs调试,之后Ctrl+C停止应用的时候,输出如下:
这里要提一下的是,在解析瞬时生命周期服务Service3的时候,示例代码中是放到一个单独的作用域中的,这是因为在通过 services.AddHostedService<Worker>(;
注入Worker的时候是注入为单例生命周期的,而在单例生命周期对象中解析其他生命周期的对象是会有问题的,这也是服务注入、解析需要注意的一个关键点。
- 在 Scoped 或 Transient 服务中解析 Singleton 服务
- 在 Scoped 或 Transient 服务中解析 Scoped 服务(不能和前面的Scoped服务相同)
如果要在单例生命周期示例中临时解析作用域、瞬时生命周期的服务,可以通过创建一个子作用域的方式。对子作用域 IServiceScope 的工作方式感兴趣的,可阅读一下这篇文章:细聊.Net Core中IServiceScope的工作方式 。
ASP.NET Core 依赖注入 | Microsoft Learn
理解ASP.NET Core - 依赖注入(Dependency Injection
目录:ASP.NET Core 系列总结
上一篇:ASP.NET Core - 依赖注入(二