AddTransient、AddScoped 和 AddSingleton 服务的差异

本文通过.NET6MVC示例详细介绍了AddTransient、AddScoped和AddSingleton三种服务生命周期的区别,展示了在请求内的行为和跨请求的稳定性。
摘要由CSDN通过智能技术生成

前言

AddTransient:每次请求服务时,都会创建一个新的服务实例。

AddScoped:在每个请求范围内,服务只被创建一次。这意味着在同一个请求中,无论多少次请求该服务,都是使用同一个实例。

AddSingleton:在整个应用程序的生命周期中,只创建一个服务实例,并且每次请求该服务时都返回这个实例。

深入理解

为了更清晰地说明,下面使用.NET6 MVC项目来举例展示这些差异:

首先考虑一个简单的接口,它代表一个或多个任务,作为一个带有唯一标识符OperationId的操作。然后根据我们如何配置这个服务的生命周期,容器将向请求类提供相同或不同的服务实例。明确请求的是哪个生命周期,为每个生命周期选项创建一个类型。

public interface IOperation
{
    string GetOperationId();
}

public interface IOperationTransient : IOperation
{
}

public interface IOperationScoped : IOperation
{
}

public interface IOperationSingleton : IOperation
{
}

public interface IOperationSingletonInstance : IOperation
{
}

然后,OperationService 类为四个接口提供了实现,所有的接口都依赖于 IOperation 接口中定义的 GetOperationId 方法。这个类为每个实例生成一个唯一的 Guid 作为其操作ID,并通过 GetOperationId 方法返回这个ID的字符串表示形式。

public class OperationService : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance
{
    private readonly Guid _id;

    public OperationService()
    {
        _id = Guid.NewGuid();
    }

    public string GetOperationId()
    {
        return _id.ToString();
    }
}

接下来,在 Program 类中注册这个服务接口的三个不同生命周期的实例:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

builder.Services.AddTransient<IOperationTransient, OperationService>();
builder.Services.AddScoped<IOperationScoped, OperationService>();
builder.Services.AddSingleton<IOperationSingleton, OperationService>();
builder.Services.AddSingleton<IOperationSingletonInstance>(new OperationService());
builder.Services.AddTransient<OperationService, OperationService>();

var app = builder.Build();

现在,在 MVC 控制器中,我们将注入这些服务,并在 Index 方法中调用它们的方法来展示不同生命周期服务的行为:

public class OperationsController : Controller
{
    private readonly OperationService _operationService;
    private readonly IOperationTransient _transientOperation;
    private readonly IOperationScoped _scopedOperation;
    private readonly IOperationSingleton _singletonOperation;
    private readonly IOperationSingletonInstance _singletonInstanceOperation;

    public OperationsController(
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _operationService = operationService;
        _transientOperation = transientOperation;
        _scopedOperation = scopedOperation;
        _singletonOperation = singletonOperation;
        _singletonInstanceOperation = singletonInstanceOperation;
    }

    public IActionResult Index()
    {
        ViewBag.TransientId = _transientOperation.GetOperationId();
        ViewBag.ScopedId = _scopedOperation.GetOperationId();
        ViewBag.SingletonId = _singletonOperation.GetOperationId();
        ViewBag.SingletonInstanceId = _singletonInstanceOperation.GetOperationId();

        return View();
    }
}

最后,在 Index.cshtml 视图中,我们将显示这些服务的 ID:

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <div style="text-align: left;">
        <h1 class="display-4">Welcome</h1>
        <p><b>Transient ID:</b> @ViewBag.TransientId</p>
        <p><b>Scoped ID:</b> @ViewBag.ScopedId</p>
        <p><b>Singleton ID:</b> @ViewBag.SingletonId</p>
        <p><b>Singleton Instance ID:</b> @ViewBag.SingletonInstanceId</p>
    </div>
</div>

现在对这个控制器操作(或方法)发出了两个独立的请求。
在这里插入图片描述
在这里插入图片描述

结论

观察OperationId的值在一个请求内部是如何变化的,以及在不同请求之间是如何变化的。

  • Transient对象总是不同的;每个控制器和每个服务都会获得一个新的实例。
  • Scoped对象在单个请求内是相同的,但在不同的请求之间是不同的。
  • Singleton对象对于每个对象和每个请求都是相同的(无论是否在ConfigureServices中提供了实例)。

这也有效映证了文章开头接触了结论。

好了,本次分享就到这里了,如果你对.Net不同生命周期(Transient、Scoped、Singleton)有了更深的认识,不妨点个赞再走吧~

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值