etc./StackOverFlow

AddTransient, AddScoped 및 AddSingleton 서비스 차이점

청렴결백한 만능 재주꾼 2022. 3. 17. 08:08
반응형

질문자 :Elvin Mammadov


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

일시적인 개체는 항상 다릅니다. 모든 컨트롤러와 모든 서비스에 새 인스턴스가 제공됩니다.

범위가 지정된 개체는 요청 내에서 동일하지만 다른 요청에서 다릅니다.

싱글톤 객체는 모든 객체와 모든 요청에 대해 동일합니다.

더 명확한 설명을 위해 .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 { } }

우리는 생성자에서 GUID를 허용하거나 제공되지 않은 경우 새 GUID를 Operation 사용하여 이러한 인터페이스를 구현합니다.

 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 인 특정 인스턴스를 사용하고 있으므로 이 유형이 사용 중일 때 명확해질 것입니다. 또한 다른 각각의 Operation OperationService 를 등록하여 이 서비스가 각 작업 유형에 대해 컨트롤러와 동일한 인스턴스를 가져오는지 아니면 새 인스턴스를 가져오는지 여부를 요청 내에서 명확하게 알 수 있습니다. 이 서비스는 종속성을 속성으로 노출하여 뷰에 표시할 수 있습니다.

 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 값이 요청 내에서 그리고 요청 간에 달라지는지 관찰하십시오.

  • 일시적인 개체는 항상 다릅니다. 모든 컨트롤러와 모든 서비스에 새 인스턴스가 제공됩니다.

  • 범위가 지정된 개체는 요청 내에서 동일하지만 다른 요청에서 다릅니다.

  • Singleton 개체는 모든 개체 및 모든 요청에 대해 동일합니다(인스턴스가 ConfigureServices 에서 제공되는지 여부에 관계 없음).


akazemis

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

애플리케이션 전체에 단일 인스턴스를 생성하는 싱글 톤. 처음으로 인스턴스를 만들고 모든 호출에서 동일한 개체를 재사용합니다.

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

임시 평생 서비스는 요청할 때마다 생성됩니다. 이 수명은 경량의 상태 비저장 서비스에 가장 적합합니다.

여기에서 차이점을 확인하기 위한 예제와 찾을 수 있습니다.

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

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

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

ASP.NET Core의 종속성 주입


akazemis

어느 것을 사용할 것인가

과도 현상

  • 매번 생성되기 때문에 더 많은 메모리 와 리소스를 사용하고 성능에 부정적인 영향을 미칠 수 있습니다.
  • 상태가 거의 또는 전혀 없는 경량 서비스에 이것을 사용합니다.

범위 지정

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

하나씩 일어나는 것

  • 이러한 서비스의 메모리 누수는 시간이 지남에 따라 누적됩니다.
  • 또한 한 번 생성되면 모든 곳에서 재사용되므로 메모리 효율적입니다.

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

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

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

bereket gebredingle

Transient, scopedsingleton 은 동일한 유형의 여러 개체를 주입해야 하는 경우 ASP.NET MVC 코어 DI(종속성 주입)에서 개체 생성 프로세스를 정의합니다. 의존성 주입이 처음인 경우 이 DI IoC 비디오를 볼 수 있습니다.

생성자에서 두 개의 "IDal" 인스턴스를 요청한 아래 컨트롤러 코드를 볼 수 있습니다. Transient, ScopedSingleton 은 동일한 인스턴스가 "_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 값을 표시한 스냅샷 이미지입니다.

여기에 이미지 설명 입력

범위 지정: 범위 지정에서는 단일 요청 및 응답에 동일한 개체 인스턴스가 주입됩니다.

여기에 이미지 설명 입력

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

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

여기에 이미지 설명 입력

위의 이미지는 내가 뭄바이에서 ASP.NET MVC 교육을 받을 때 SBSS 팀에서 그린 것입니다. 위의 이미지를 만들어주신 SBSS팀에 깊은 감사를 드립니다.


Shivprasad Koirala

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

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

 public MyConsumingClass(IDependency dependency)

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


user1969177

AddSingleton()

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

범위 추가()

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

AddTransient()

임시 서비스를 사용하면 동일한 HTTP 요청 범위에 있든 다른 HTTP 요청에 걸쳐 있든 서비스 인스턴스가 요청될 때마다 새 인스턴스가 제공됩니다.


Yasser Shaikh

이 이미지는 이 개념을 잘 보여줍니다. 불행히도 이 이미지의 원본 소스를 찾을 수 없었지만 누군가가 그것을 만들었습니다. 그는 이 개념을 이미지의 형태로 아주 잘 보여주었습니다. 여기에 이미지 설명 입력


Hamed Naeemaei

이 질문에 대한 답을 찾은 후 여러분과 공유하고 싶은 예가 있는 훌륭한 설명을 찾았습니다.

여기 에서 차이점을 보여주는 비디오를 볼 수 있습니다.

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

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

홈 컨트롤러

 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 , AddScopedAddTransient 간에 전환하면 매번 다른 결과를 얻을 수 있으므로 이를 이해하는 데 도움이 됩니다.

AddSingleton() - 이름에서 알 수 있듯이 AddSingleton() 메서드는 싱글톤 서비스를 생성합니다. Singleton 서비스는 처음 요청될 때 생성됩니다. 이 동일한 인스턴스는 모든 후속 요청에서 사용됩니다. 따라서 일반적으로 Singleton 서비스는 애플리케이션당 한 번만 생성되며 해당 단일 인스턴스는 애플리케이션 수명 내내 사용됩니다.

AddTransient() - 이 메서드는 일시적인 서비스를 만듭니다. 요청될 때마다 임시 서비스의 새 인스턴스가 생성됩니다.

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


Offir

출처 : http:www.stackoverflow.com/questions/38138100/addtransient-addscoped-and-addsingleton-services-differences

반응형