[C#] AddTransient, AddScoped 및 AddSingleton Services의 차이점

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



답변

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를 사용합니다.

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유형 과을 요청 하는 샘플이 포함되어 OperationService있습니다. Index액션은 컨트롤러의 서비스의 모든 표시 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)


답변

.NET의 의존성 주입에는 세 가지 주요 수명이 있습니다.

단일 응용 프로그램 전체에 단일 인스턴스를 만듭니다. 처음으로 인스턴스를 생성하고 모든 호출에서 동일한 객체를 재사용합니다.

범위 수명 서비스는 범위 내에서 요청 당 한 번 작성됩니다. 현재 범위의 싱글 톤과 같습니다. 예를 들어, MVC에서는 각 HTTP 요청에 대해 하나의 인스턴스를 작성하지만 동일한 웹 요청 내의 다른 호출에서 동일한 인스턴스를 사용합니다.

과도 현상 수명 서비스는 요청 될 때마다 생성됩니다. 이 수명은 가벼운 상태 비 저장 서비스에 가장 적합합니다.

차이점을 확인할 수있는 예제와 예제는 다음과 같습니다.

6 단계의 ASP.NET 5 MVC6 종속성 주입 (불량 링크로 인한 웹 아카이브 링크)

의존성 주입 준비 ASP.NET : ASP.NET 5

그리고 이것은 공식 문서에 대한 링크입니다.

ASP.NET Core에서 종속성 주입


답변

과도, 범위 및 싱글 톤은 동일한 유형의 여러 개체를 주입해야하는 경우 ASP.NET MVC 코어 DI에서 개체 생성 프로세스를 정의합니다. 의존성 주입을 처음 사용하는 경우이 DI IoC 비디오를 볼 수 있습니다 .

생성자에서 “IDal”의 두 인스턴스를 요청한 아래 컨트롤러 코드를 볼 수 있습니다. Transient, Scoped 및 Singleton은 동일한 인스턴스가 “_dal”및 “_dal1″에 주입되는지 또는 다른지 여부를 정의합니다.

public class CustomerController : Controller
{
    IDal dal = null;

    public CustomerController(IDal _dal,
                              IDal _dal1)
    {
        dal = _dal;
        // DI of MVC core
        // inversion of control
    }
}

과도 상태 : 과도 상태에서는 단일 요청 및 응답으로 새 객체 인스턴스가 주입됩니다. 아래는 GUID 값을 표시 한 스냅 샷 이미지입니다.

여기에 이미지 설명을 입력하십시오

범위 : 범위에서, 동일한 객체 인스턴스가 단일 요청 및 응답으로 주입됩니다.

여기에 이미지 설명을 입력하십시오

싱글 톤 : 싱글 톤에서는 모든 요청과 응답에 동일한 객체가 주입됩니다. 이 경우 객체의 하나의 전역 인스턴스가 생성됩니다.

아래는 위의 기본 사항을 시각적으로 설명하는 간단한 다이어그램입니다.

MVC DI 이미지

위 이미지는 뭄바이에서 ASP.NET MVC 교육을받을 때 SBSS 팀이 그린 것 입니다. 위 이미지를 만든 SBSS 팀에게 큰 감사를드립니다.


답변

  • 싱글 톤은 애플리케이션 도메인 수명 동안 단일 인스턴스입니다.
  • 범위 지정은 범위 지정된 요청 기간 동안 단일 인스턴스이며 이는 ASP.NET의 HTTP 요청 당을 의미 합니다.
  • 임시는 코드 요청 당 단일 인스턴스입니다 .

일반적으로 코드 요청은 다음과 같이 생성자 매개 변수를 통해 이루어져야합니다.

public MyConsumingClass(IDependency dependency)

나는 DI의 맥락에서 “서비스”가 RESTful 서비스를 의미하지 않는다는 @akazemis의 대답에서 지적하고 싶었다. 서비스는 기능을 제공하는 종속성의 구현입니다.


답변

AddSingleton ()

AddSingleton ()은 처음 요청 될 때 서비스의 단일 인스턴스를 작성하고 해당 서비스가 필요한 모든 장소에서 동일한 인스턴스를 재사용합니다.

AddScoped ()

범위가 지정된 서비스에서 모든 HTTP 요청과 함께 새 인스턴스를 얻습니다. 그러나 동일한 HTTP 요청 내에서보기 및 컨트롤러와 같이 여러 위치에서 서비스가 필요한 경우 해당 HTTP 요청의 전체 범위에 대해 동일한 인스턴스가 제공됩니다. 그러나 모든 새로운 HTTP 요청은 서비스의 새로운 인스턴스를 얻게됩니다.

AddTransient ()

임시 서비스를 사용하면 서비스 인스턴스가 동일한 HTTP 요청 범위에 있는지 또는 다른 HTTP 요청에 관계없이 요청 될 때마다 새 인스턴스가 제공됩니다.


답변

이 질문에 대한 답을 찾은 후에 나는 당신과 공유하고 싶은 예를 통해 훌륭한 설명을 발견했습니다.

당신은 차이점을 보여 비디오 볼 수 있습니다 여기를

이 예제에는 다음과 같은 코드가 있습니다.

public interface IEmployeeRepository
{
    IEnumerable<Employee> GetAllEmployees();
    Employee Add(Employee employee);
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MockEmployeeRepository : IEmployeeRepository
{
    private List<Employee> _employeeList;

    public MockEmployeeRepository()
    {
        _employeeList = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "Mary" },
        new Employee() { Id = 2, Name = "John" },
        new Employee() { Id = 3, Name = "Sam" },
    };
    }

    public Employee Add(Employee employee)
    {
        employee.Id = _employeeList.Max(e => e.Id) + 1;
        _employeeList.Add(employee);
        return employee;
    }

    public IEnumerable<Employee> GetAllEmployees()
    {
        return _employeeList;
    }
}

HomeController

public class HomeController : Controller
{
    private IEmployeeRepository _employeeRepository;

    public HomeController(IEmployeeRepository employeeRepository)
    {
        _employeeRepository = employeeRepository;
    }

    [HttpGet]
    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(Employee employee)
    {
        if (ModelState.IsValid)
        {
            Employee newEmployee = _employeeRepository.Add(employee);
        }

        return View();
    }
}

뷰 작성

@model Employee
@inject IEmployeeRepository empRepository

<form asp-controller="home" asp-action="create" method="post">
    <div>
        <label asp-for="Name"></label>
        <div>
            <input asp-for="Name">
        </div>
    </div>

    <div>
        <button type="submit">Create</button>
    </div>

    <div>
        Total Employees Count = @empRepository.GetAllEmployees().Count().ToString()
    </div>
</form>

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>();
}

사이보기 및 스위치에서 생성 버튼이 코드를 눌러를 복사 – 붙여 넣기
AddSingleton, AddScoped그리고 AddTransient당신은 때마다이 설명을 이해하는 데 도움이 될 것입니다 다른 결과를 얻을 것이다 :

AddSingleton () -이름에서 알 수 있듯이 AddSingleton () 메서드는 Singleton 서비스를 만듭니다. 싱글 톤 서비스는 처음 요청 될 때 생성됩니다. 이 동일한 인스턴스는 모든 후속 요청에서 사용됩니다. 따라서 일반적으로 Singleton 서비스는 응용 프로그램 당 한 번만 생성되며 해당 단일 인스턴스는 응용 프로그램 수명 기간 동안 사용됩니다.

AddTransient () -이 메소드는 임시 서비스를 작성합니다. Transient 서비스의 새 인스턴스는 요청 될 때마다 작성됩니다.

AddScoped () -이 메소드는 범위가 지정된 서비스를 작성합니다. 범위 내에서 요청 당 한 번씩 범위 서비스의 새 인스턴스가 작성됩니다. 예를 들어, 웹 애플리케이션에서 각 http 요청 당 하나의 인스턴스를 작성하지만 동일한 웹 요청 내의 다른 호출에서 동일한 인스턴스를 사용합니다.


답변

사용할 것

과도 현상

  • 매번 생성되므로 더 많은 메모리 와 리소스를 사용하고 성능에 부정적인 영향을 줄 수 있습니다
  • 상태 가 거의 또는 전혀없는 가벼운 서비스에 이것을 사용하십시오 .

범위가 지정된

  • 요청 내에서 상태를 유지하려는 경우 더 나은 옵션입니다.

하나씩 일어나는 것

  • 이러한 서비스에서 메모리 누출은 시간이 지남에 따라 쌓입니다.
  • 또한 언제 어디서나 재사용 할 수있어 메모리 효율성이 뛰어납니다.

애플리케이션 전체 상태를 유지해야하는 경우 싱글 톤을 사용하십시오. 응용 프로그램 구성 또는 매개 변수, 로깅 서비스, 데이터 캐싱은 싱글 톤을 사용할 수있는 몇 가지 예입니다.

수명이 다른 서비스를 다른 서비스에 주입

  1. Scoped & Transient 서비스를 Singleton 서비스에 주입하지 마십시오. (이 기능은 일시적 또는 범위가 지정된 서비스를 싱글 톤으로 효과적으로 변환합니다.)
  2. 일시적 서비스를 범위 서비스에 주입하지 마십시오 (이는 일시적 서비스를 범위 서비스 로 변환합니다).