싱글톤 내에서 범위 지정 서비스 사용

부인 성명



싱글톤 내에서 범위가 지정된 서비스를 사용하려고 시도하는 것(또는 그 문제에 대해 수명이 긴 서비스 내에서 수명이 짧은 서비스를 사용하는 것!)은 일반적으로 나쁜 생각이라는 말로 이 토론을 시작하고 싶습니다. 대부분의 DI(종속성 주입) 컨테이너가 이를 중지시키려는 데는 이유가 있습니다. 싱글톤 내에서 범위가 지정된 서비스를 사용하려고 하면 Captive Dependencies 으로 알려진 문제가 발생할 수 있으며, 이는 모든 종류의 고약한 버그와 메모리 누수를 유발할 수 있습니다.

범위가 지정된 서비스를 싱글톤에 삽입하려는 상황에 처한 경우 일반적으로 code smell이며 해당 종속성을 피하기 위해 서비스 리팩터링을 심각하게 고려해야 합니다.

그럼에도 불구하고 때로는 싱글톤 내에서 범위 지정 서비스를 사용해야 하는 정당한 이유가 있습니다. 이것이 귀하의 사용 사례에 해당된다고 생각되면 계속 읽으십시오.

소개



서비스를 다른 서비스에 삽입하려고 시도했지만 다음 예외가 발생했습니까?:

InvalidOperationException: Cannot resolve scoped service 'IMyScopedService' from root provider.


그렇다면 범위가 지정된 서비스를 싱글톤 서비스에 삽입하려고 할 수 있음을 나타내는 좋은 표시입니다. DI 컨테이너가 종속 종속성으로부터 사용자를 보호하려고 하기 때문에 예외가 나타납니다(위 면책 조항 참조). 일반적으로 DI 컨테이너가 이러한 일을 하지 못하도록 막는 것이 좋지만 때로는 그렇게 해야 할 때도 있습니다.

나는 최근에 hosted service in ASP.NET Core을 만들려고 할 때 이것을 발견했습니다. 호스팅된 서비스를 사용하면 장기 실행 백그라운드 작업을 생성할 수 있으며 기본적으로 싱글톤 서비스처럼 작동합니다( with a few minor caveats ).

내 백그라운드 작업 중 일부는 다른 서비스를 사용해야 하며 대부분은 임시/범위입니다. 그러나 이러한 서비스를 내 호스팅 서비스의 생성자에 주입하려고 했을 때 위와 비슷한 예외가 발생했습니다.

문제



ASP.NET Core DI 컨테이너에는 싱글톤 서비스를 확인하는 데 사용되는 루트IServiceProvider가 있습니다. 범위가 지정된 서비스의 경우 컨테이너는 먼저 새 범위를 만들어야 하며 각 범위는 고유합니다IServiceProvider. 범위 지정 서비스는 자체 범위 내에서 IServiceProvider에서만 액세스할 수 있으며 루트IServiceProvider에서는 액세스할 수 없습니다.



해결책



싱글톤 내에서 범위 지정 서비스를 사용하려면 수동으로 범위를 만들어야 합니다. IServiceScopeFactory를 싱글톤 서비스에 주입하여 새 범위를 생성할 수 있습니다(IServiceScopeFactory 자체가 싱글톤이므로 이것이 작동하는 이유입니다). IServiceScopeFactory에는 새 범위 인스턴스를 만드는 데 사용되는 CreateScope 메서드가 있습니다.

public class MySingletonService
{
  private readonly IServiceScopeFactory _serviceScopeFactory;

  public MySingletonService(IServiceScopeFactory serviceScopeFactory)
  {
    _serviceScopeFactory = serviceScopeFactory;
  }

  public void Execute()
  {
    using (var scope = _serviceScopeFactory.CreateScope())
    {
      var myScopedService = scope.ServiceProvider.GetService<IMyScopedService>();

      myScopedService.DoSomething();
    }
  }
}


생성된 범위에는 범위가 지정된 서비스를 확인하기 위해 액세스할 수 있는 자체IServiceProvider가 있습니다.

범위가 필요한 기간 동안만 존재하고 작업을 마친 후에는 적절하게 폐기되도록 하는 것이 중요합니다. 이는 포로 종속성 문제를 방지하기 위한 것입니다(이 문서의 시작 부분에서 설명한 대로). 따라서 다음을 권장합니다.
  • 사용하려는 메소드 내에서만 범위를 정의하십시오. 싱글톤 서비스의 다른 곳에서 재사용하기 위해 필드에 할당하고 싶을 수도 있지만 이 경우에도 종속 종속성이 발생합니다.
  • 범위를 using 문으로 래핑합니다. 이렇게 하면 작업을 마친 후 스코프를 적절하게 폐기할 수 있습니다.

  • 결론



    싱글톤 내에서 범위가 지정된 서비스를 해결하려는 시도는 종종 코드를 리팩터링해야 한다는 신호일 수 있지만 때로는 여전히 리팩토링이 필요합니다.

    범위가 지정된 서비스는 범위를 만들고 범위의 IServiceProvider를 사용하여 싱글톤에서 사용할 수 있습니다. 그러나 종속 종속성을 방지하기 위해 범위를 사용한 후에는 범위를 정리해야 합니다.

    이 글이 도움이 되셨다면 좋아요와 공유 부탁드립니다. 이와 같은 더 많은 콘텐츠를 보려면 이 블로그 및 를 팔로우하십시오. 원한다면 할 수도 있습니다 buy me a coffee ! 😊

    좋은 웹페이지 즐겨찾기