首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >AddTransient、AddScoped和AddSingleton服务的区别

AddTransient、AddScoped和AddSingleton服务的区别
EN

Stack Overflow用户
提问于 2016-07-01 14:03:03
回答 10查看 785.6K关注 0票数 1.5K

我想在ASP.NET核心中实现dependency injection (DI)。因此,在将此代码添加到ConfigureServices方法后,这两种方法都可以工作。

ASP.NET核心中的services.AddTransientservice.AddScoped方法有什么不同?

代码语言:javascript
复制
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.

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

回答 10

Stack Overflow用户

回答已采纳

发布于 2016-07-01 15:27:11

TL;DR

瞬态对象总是不同的;每个控制器和每个服务都会有一个新的实例。

作用域对象在一个请求中是相同的,但在不同的请求中是不同的。

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

为了得到更多的说明,.NET documentation中的这个例子展示了其中的区别:

根据我们如何配置此服务的生存期,容器将向请求类提供相同或不同的服务实例。为了明确请求哪个生存期,我们将为每个生存期选项创建一个类型:

代码语言:javascript
复制
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
    {
    }
}

代码语言:javascript
复制
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中,每种类型都根据其命名的生存期添加到容器中:

代码语言:javascript
复制
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的特定实例,因此可以清楚地知道何时使用了此类型。我们还注册了一个依赖于每个其他Operation类型的OperationService,以便在请求中可以清楚地知道该服务是获取与控制器相同的实例,还是为每个操作类型获取一个新实例。此服务所做的全部工作就是将其依赖项公开为属性,以便可以在视图中显示它们。

代码语言:javascript
复制
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;
        }
    }
}

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

代码语言:javascript
复制
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)

中是否提供了实例

票数 2.6K
EN

Stack Overflow用户

发布于 2016-07-01 14:29:19

在.NET的依赖注入中,有三个主要的生命周期:

单例,在整个应用程序中创建单个实例。它第一次创建实例,并在所有调用中重用同一对象。

作用域内的每个请求都会创建一次作用域生存期服务。等同于当前作用域中的单例。例如,在MVC中,它为每个HTTP请求创建一个实例,但它在同一web请求内的其他调用中使用相同的实例。

每次请求临时生存期服务时都会创建这些服务。此生命周期最适合于轻量级的无状态服务。

在这里,您可以找到和示例来了解其中的区别:

(由于死链接而导致web存档链接)

这是官方文档的链接:

票数 415
EN

Stack Overflow用户

发布于 2020-05-11 17:15:56

使用哪一个?

瞬态

对于

  • ,因为每次创建它们都会使用更多的内存、和资源,并且可能会对performance

  • use造成负面的影响,这对轻量级服务的影响很小,甚至没有state.

作用域

当您想要维护请求中的状态时,

  • 是更好的选择。

单例

随着时间的推移,这些服务中的

  • 内存泄漏将会累积。
  • 还会提高内存效率,因为它们一旦在任何地方重复使用,就会创建。

在需要维护应用程序范围状态的地方使用单例。应用程序配置或参数、日志记录服务、数据缓存是您可以使用单例的一些示例。

将具有不同生命周期的服务注入另一个服务

  1. Never将作用域和临时服务注入到单例服务中。(这将有效地将临时或临时服务转换为单例服务。)

  1. Never将临时服务注入作用域服务(这会将临时服务转换为作用域服务。)
票数 190
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38138100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档