温馨提示:本文翻译自stackoverflow.com,查看原文请点击:c# - AddTransient, AddScoped and AddSingleton Services Differences
.net-core asp.net-core c#

c# - AddTransient,AddScoped和AddSingleton服务的区别

发布于 2020-09-01 01:04:20

我想在ASP.NET Core中实现依赖项注入(DI)。因此,将这段代码添加到ConfigureServices方法之后,两种方法都可以工作。

ASP.NET Core中services.AddTransientservice.AddScoped方法之间有什么区别

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddScoped<IEmailSender, AuthMessageSender>();
}

查看更多

提问者
Elvin Mammadov
被浏览
423
26.3k 2020-03-08 05:12

TL; DR

瞬态对象总是不同的。为每个控制器和每个服务提供一个新实例。

范围对象在一个请求中是相同的,但在不同的请求中是不同的。

每个对象和每个请求的单例对象都相同。

为了进一步说明,来自ASP.NET文档的此示例显示了以下区别:

为了说明这些生存期和注册选项之间的区别,请考虑一个简单的界面,该界面将一个或多个任务表示为具有唯一标识符的操作OperationId根据我们如何配置此服务的生存期,容器将为请求的类提供相同或不同的服务实例。为了清楚说明请求哪个生存期,我们将为每个生存期创建一个类型的选项:

using System;

namespace DependencyInjectionSample.Interfaces
{
    public interface IOperation
    {
        Guid OperationId { get; }
    }

    public interface IOperationTransient : IOperation
    {
    }

    public interface IOperationScoped : IOperation
    {
    }

    public interface IOperationSingleton : IOperation
    {
    }

    public interface IOperationSingletonInstance : IOperation
    {
    }
}

我们使用单个类()来实现这些接口,该类Operation在其构造函数中接受一个GUID;如果未提供任何GUID,则使用新的GUID:

using System;
using DependencyInjectionSample.Interfaces;
namespace DependencyInjectionSample.Classes
{
    public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance
    {
        Guid _guid;
        public Operation() : this(Guid.NewGuid())
        {

        }

        public Operation(Guid guid)
        {
            _guid = guid;
        }

        public Guid OperationId => _guid;
    }
}

接下来,在中ConfigureServices,根据其命名生存期将每种类型添加到容器中:

services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();

请注意,该IOperationSingletonInstance服务正在使用ID为的特定实例Guid.Empty,因此使用此类型时将很清楚。我们还注册了一个OperationService依赖于其他每种Operation类型的,因此对于每种操作类型,该请求将清楚地表明此服务是与控制器使用相同的实例,还是获得新的实例。该服务所做的全部工作就是将其依赖项公开为属性,以便可以在视图中显示它们。

using DependencyInjectionSample.Interfaces;

namespace DependencyInjectionSample.Services
{
    public class OperationService
    {
        public IOperationTransient TransientOperation { get; }
        public IOperationScoped ScopedOperation { get; }
        public IOperationSingleton SingletonOperation { get; }
        public IOperationSingletonInstance SingletonInstanceOperation { get; }

        public OperationService(IOperationTransient transientOperation,
            IOperationScoped scopedOperation,
            IOperationSingleton singletonOperation,
            IOperationSingletonInstance instanceOperation)
        {
            TransientOperation = transientOperation;
            ScopedOperation = scopedOperation;
            SingletonOperation = singletonOperation;
            SingletonInstanceOperation = instanceOperation;
        }
    }
}

为了演示对应用程序的各个单独请求之内和之间的对象生存期,该示例包括一个OperationsController请求每种类型的请求IOperation以及一个请求OperationServiceIndex然后,操作将显示所有控制器和服务的OperationId值。

using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
using Microsoft.AspNetCore.Mvc;

namespace DependencyInjectionSample.Controllers
{
    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 contains controller-requested services
            ViewBag.Transient = _transientOperation;
            ViewBag.Scoped = _scopedOperation;
            ViewBag.Singleton = _singletonOperation;
            ViewBag.SingletonInstance = _singletonInstanceOperation;

            // Operation service has its own requested services
            ViewBag.Service = _operationService;
            return View();
        }
    }
}

现在,对此控制器操作提出了两个单独的请求:

第一个请求

第二个请求

观察哪个OperationId值在请求内以及请求之间变化。

  • 瞬态对象总是不同的。为每个控制器和每个服务提供一个新实例。

  • 范围对象在一个请求中是相同的,但在不同的请求中是不同的

  • 每个对象和每个请求的单例对象都相同(无论是否在中提供了实例ConfigureServices