ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

.NET 中的依赖注入(四):生命周期

2022-01-17 01:35:06  阅读:231  来源: 互联网

标签:... 生命周期 Always 依赖 Call scope Scope NET ITransientOperation


本文示例代码,均采用 .NET 6,具体的代码可以在这个仓库 Articles.DI 中获取。

前面的文章中,在注册服务时,统一使用了 services.AddSingleton<TService, TImplementation>() 的形式来注册服务,这个方法的具体含义是什么?有没有其他类似的方法?而且我们还有一个疑问,容器在构造服务时,服务的生命周期是怎么样的?服务被申请一次,就构造一次吗?还是整个程序周期,只构造一次?如果我们要自定义每个服务有不同的生命周期时,又该怎么做?下面,我们将一起探寻服务的生命周期。

生命周期

注册到容器时,服务的生命周期分为三种

生命周期 何时创建 调用方法
瞬时 / Transient 每次请求,都会创建一个新的实例 AddTransient()
范围 / Scoped 在指定的范围内,第一次请求时会创建一个实例
重复请求时,会返回同一个实例
AddScoped()
单例 / Singleton 在整个程序生命周期,只会创建一次
后续所有请求,都会返回同一个实例
AddSingleton()

参考实际代码,我们可以更直观的理解依赖注入中的三种生命周期,下面的代码可以在微软的 .NET 文档中找到对应的文章——教程:在 .NET 中使用依赖注入。或者可以在这个仓库中直接查看获取源码

// https://github.com/alva-lin/Articles.DI/tree/master/ConsoleApp1
// 01. 声明接口以及实现类
public interface IOperation
{
    string OperationId { get; }
}

public interface ITransientOperation : IOperation {}

public interface IScopedOperation : IOperation {}

public interface ISingletonOperation : IOperation {}

public class DefaultOperation
    : ITransientOperation, IScopedOperation, ISingletonOperation
{
    // 创建一个 Guid,取最后 4 个字符
    public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}
// 02. 创建一个服务,它依赖上面几个 Operation
public class OperationLogger
{
    private readonly ITransientOperation _transientOperation;
    private readonly IScopedOperation    _scopedOperation;
    private readonly ISingletonOperation _singletonOperation;

    public OperationLogger(ITransientOperation transientOperation,
                           IScopedOperation    scopedOperation,
                           ISingletonOperation singletonOperation)
    {
        _transientOperation = transientOperation;
        _scopedOperation    = scopedOperation;
        _singletonOperation = singletonOperation;
    }

    public void LogOperations(string scope)
    {
        LogOperation(_transientOperation, scope, "Always different");
        LogOperation(_scopedOperation, scope, "Changes only with scope");
        LogOperation(_singletonOperation, scope, "Always the same");
    }

    private static void LogOperation<T>(T operation, string scope, string message)
        where T : IOperation
    {
        Console.WriteLine($"{scope}: {typeof(T).Name,-19} [{operation.OperationId} {message,-23}]");
    }
}
// 03. 注册服务并启动程序
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateDefaultBuilder(args)
   .ConfigureServices(services =>
    {
        // 将三种 Operation 分别注册为三种声明周期
        services.AddTransient<OperationLogger>()
           .AddTransient<ITransientOperation, DefaultOperation>()
           .AddScoped<IScopedOperation, DefaultOperation>()
           .AddSingleton<ISingletonOperation, DefaultOperation>();
    })
   .Build();

ExemplifyScoping(host.Services, "Scope 1");
ExemplifyScoping(host.Services, "Scope 2");

await host.RunAsync();


static void ExemplifyScoping(IServiceProvider services, string scope)
{
    using IServiceScope serviceScope = services.CreateScope();
    IServiceProvider    provider     = serviceScope.ServiceProvider;

    var logger = provider.GetRequiredService<OperationLogger>();
    logger.LogOperations($"{scope}: Call 1 ...");
    Console.WriteLine();

    logger = provider.GetRequiredService<OperationLogger>();
    logger.LogOperations($"{scope}: Call 2 ...");
    Console.WriteLine();
}

运行上述代码,可以获得下面的结果

Scope 1: Call 1 ...: ITransientOperation [b672 Always different       ]
Scope 1: Call 1 ...: IScopedOperation    [afd8 Changes only with scope]
Scope 1: Call 1 ...: ISingletonOperation [21b3 Always the same        ]

Scope 1: Call 2 ...: ITransientOperation [b6fc Always different       ]
Scope 1: Call 2 ...: IScopedOperation    [afd8 Changes only with scope]
Scope 1: Call 2 ...: ISingletonOperation [21b3 Always the same        ]

Scope 2: Call 1 ...: ITransientOperation [ef31 Always different       ]
Scope 2: Call 1 ...: IScopedOperation    [46d1 Changes only with scope]
Scope 2: Call 1 ...: ISingletonOperation [21b3 Always the same        ]
 
Scope 2: Call 2 ...: ITransientOperation [9864 Always different       ]
Scope 2: Call 2 ...: IScopedOperation    [46d1 Changes only with scope]
Scope 2: Call 2 ...: ISingletonOperation [21b3 Always the same        ]

比对程序输出的日志,可以看出,每个 ITransientOperation 的输出都会不一样;而 IScopedOperation 在相同的范围内输出内容一样,在不同的范围间输出内容不同;最后一个 ISingletonOperation,每次的输出都是相同的。这样的输出结果,也符合我们前面的表格展示内容。

参考链接

.NET 中的依赖关系注入

教程:在 .NET 中使用依赖注入

标签:...,生命周期,Always,依赖,Call,scope,Scope,NET,ITransientOperation
来源: https://www.cnblogs.com/asjun/p/15811915.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有