ASP.NET Core - 依赖注入(三)

科技资讯 投稿 6500 0 评论

ASP.NET Core - 依赖注入(三)

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 - 依赖注入(二

编程笔记 » ASP.NET Core - 依赖注入(三)

赞同 (34) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽