AddTransient、AddScoped 和 AddSingleton 服务差异 [英] AddTransient, AddScoped and AddSingleton Services Differences

查看:16
本文介绍了AddTransient、AddScoped 和 AddSingleton 服务差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 ASP.NET Core 中实现

观察哪些 OperationId 值在请求内和请求之间变化.

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

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

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

I want to implement dependency injection (DI) in ASP.NET Core. So after adding this code to ConfigureServices method, both ways work.

What is the difference between the services.AddTransient and service.AddScoped methods in ASP.NET Core?

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

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

解决方案

TL;DR

Transient objects are always different; a new instance is provided to every controller and every service.

Scoped objects are the same within a request, but different across different requests.

Singleton objects are the same for every object and every request.

For more clarification, this example from .NET documentation shows the difference:

To demonstrate the difference between these lifetime and registration options, consider a simple interface that represents one or more tasks as an operation with a unique identifier, OperationId. Depending on how we configure the lifetime for this service, the container will provide either the same or different instances of the service to the requesting class. To make it clear which lifetime is being requested, we will create one type per lifetime option:

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
    {
    }
}

We implement these interfaces using a single class, Operation, that accepts a GUID in its constructor, or uses a new GUID if none is provided:

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;
    }
}

Next, in ConfigureServices, each type is added to the container according to its named lifetime:

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

Note that the IOperationSingletonInstance service is using a specific instance with a known ID of Guid.Empty, so it will be clear when this type is in use. We have also registered an OperationService that depends on each of the other Operation types, so that it will be clear within a request whether this service is getting the same instance as the controller, or a new one, for each operation type. All this service does is expose its dependencies as properties, so they can be displayed in the view.

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;
        }
    }
}

To demonstrate the object lifetimes within and between separate individual requests to the application, the sample includes an OperationsController that requests each kind of IOperation type as well as an OperationService. The Index action then displays all of the controller’s and service’s OperationId values.

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();
        }
    }
}

Now two separate requests are made to this controller action:

Observe which of the OperationId values varies within a request, and between requests.

  • Transient objects are always different; a new instance is provided to every controller and every service.

  • Scoped objects are the same within a request, but different across different requests

  • Singleton objects are the same for every object and every request (regardless of whether an instance is provided in ConfigureServices)

这篇关于AddTransient、AddScoped 和 AddSingleton 服务差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆