ASP.NET 코어 의존 주입(구조 함수 주입,속성 주입 등)

10168 단어 C#
ASP.NET Core 의존 주입 에 익숙 하지 않다 면 먼저 글 을 읽 으 세 요. ASP.NET Core 에 의존 주입 사용
 
구조 함수 주입
구조 함수 주입 은 서비스 구축 에 있어 서 서비스 의존 을 정의 하고 가 져 오 는 데 자주 사용 된다.예 를 들 면:
  public class ProductService
  {
      private readonly IProductRepository _productRepository;
      public ProductService(IProductRepository productRepository)
      {
          _productRepository = productRepository;
      }
      public void Delete(int id)
      {
         _productRepository.Delete(id);
     }
 }

ProductService 는 IProductRepository 를 구조 함수 에 의존 한 다음 Delete 방법 내부 에서 이 의존 도 를 사용 합 니 다.
실천 지침:
  • 은 서비스 구조 함수 에서 필요 한 의존 도 를 명확 하 게 정의 한다.따라서 이 서 비 스 는 이러한 의존 이 없 을 때 구 조 될 수 없다.
  • 은 읽 기 전용(readonly)필드 나 속성 에 주 입 된 의존 대 가 를 부여 합 니 다.

  • 속성 주입
    ASP.NET Core 의 표준 의존 주입 용 기 는 속성 주입 을 지원 하지 않 습 니 다.하지만 다른 용 기 를 사용 하여 속성 주입 을 지원 할 수 있 습 니 다.예 를 들 면:
     
      using Microsoft.Extensions.Logging;
      using Microsoft.Extensions.Logging.Abstractions;
      namespace MyApp
      {
          public class ProductService
          {
              public ILogger Logger { get; set; }
              private readonly IProductRepository _productRepository;
              public ProductService(IProductRepository productRepository)
             {
                 _productRepository = productRepository;
                 Logger = NullLogger.Instance;
             }
             public void Delete(int id)
             {
                 _productRepository.Delete(id);
                 Logger.LogInformation(
                     $"Deleted a product with id = {id}");
             }
         }
     }
    

    ProductService 는 공개 setter 가 있 는 Logger 속성 을 정의 합 니 다.
    주입 용기 에 의존 하면 Logger 속성 을 설정 할 수 있 습 니 다.사용 가능 하 다 면(DI 용기 에 등록 되 어 있 습 니 다).
    실천 지침:
  • 은 선택 가능 한 사용 속성 에 만 주입 합 니 다.이것 은 당신 의 서비스 가 이러한 의존 을 제공 하지 않 았 을 때 정상적으로 일 할 수 있다 는 것 을 의미한다.
  • 가능 하 다 면 빈 대상 모드 를 사용 하 십시오.그렇지 않 으 면 이 의존 도 를 사용 할 때 null
  • 인지 항상 확인 합 니 다.
    서비스 포 지 셔 닝 머 신
    서비스 포 지 셔 닝 모드 는 의존 관 계 를 얻 는 또 다른 방식 이다.예 를 들 면:
     
      public class ProductService
      {
          private readonly IProductRepository _productRepository;
          private readonly ILogger _logger;
          public ProductService(IServiceProvider serviceProvider)
          {
              _productRepository = serviceProvider
                .GetRequiredService();
              _logger = serviceProvider
               .GetService>() ??
                 NullLogger.Instance;
         }
         public void Delete(int id)
         {
             _productRepository.Delete(id);
             _logger.LogInformation($"Deleted a product with id = {id}");
         }
     }
    

    ProductService 가 주입 되 었 습 니 다. IServiceProvider 의존 도 를 분석 하고 사용 합 니 다.요청 한 의존 도가 등록 되 지 않 으 면 GetRequired Service 에 이상 이 발생 합 니 다.이 경우 GetService 는 null 로 만 돌아 간 다 는 얘 기다.
    구조 함수 내부 에서 서 비 스 를 분석 할 때 서비스의 방출 에 따라 방출 됩 니 다.따라서 구조 함수 내부 에서 해 석 된 서비스의 방출 문제(구조 함수 주입 과 속성 주입)에 관심 을 가 질 필요 가 없다.
    실천 지침
  • 가능 한 한 서비스 포 지 셔 닝 모델 을 사용 하지 마 십시오.의존 이 명확 하지 않 기 때문이다.이 는 서비스 인 스 턴 스 를 만 드 는 동안 의존 관 계 를 쉽게 볼 수 없다 는 뜻 이다.이것 은 단원 테스트 에 있어 서 특히 중요 하 다.왜냐하면 당신 은 약간의 의존 도 를 모 의 하려 고 할 수도 있 기 때문이다.
  • 가능 하 다 면 서비스 구조 함수 에서 의존 도 를 분석 합 니 다.서비스 방법 에서 해석 하면 프로그램 이 더욱 어렵 고 오류 가 발생 하기 쉽다.나 는 다음 장 에서 문제 와 해결 방안 을 토론 할 것 이다.

  • 서비스 수명 주기
     다음은 서비스 가 ASP.NET Core 의존 주입 에서 의 수명 주기 입 니 다.
  • Transient 형식의 서 비 스 는 주입 이나 요청 할 때마다 생 성 됩 니 다.
  • Scoped 유형의 서 비 스 는 역할 영역 에 따라 생 성 됩 니 다.웹 프로그램 에서 모든 웹 요청 은 새로운 격 리 된 서비스 역할 영역 을 만 듭 니 다.이 는 Scoped 형식의 서 비 스 는 보통 웹 요청 에 따라 만들어 진 다 는 뜻 이다.
  • Singleton 유형의 서 비 스 는 DI 용기 에서 만 듭 니 다.이것 은 일반적으로 응용 프로그램 에 따라 한 번 만 만들어 진 후에 응용 프로그램의 전체 생명 주기 에 사용 된다 는 것 을 의미한다.

  •  
    DI 용 기 는 해 석 된 모든 서 비 스 를 지속 적 으로 추적 합 니 다.서비스의 생명주기 가 종 료 될 때,그것들 은 방출 되 고 소 멸 될 것 이다.
  • 서비스 에 의존 이 있 으 면 그들 도 자동 으로 방출 되 고 소각 된다.

  • 하면,만약,만약... IDisposable 인터페이스,Dispose 방법 은 서비스 가 풀 릴 때 자동 으로 호출 됩 니 다.  
    실천 지침:
  • 가능 한 한 당신 의 서 비 스 를 Transient 유형Transient 서 비 스 를 설계 하 는 것 은 간단 하기 때문이다.당신 은 보통 다 중 스 레 드 문제 와 메모리 누 출 문제 에 관심 을 가 질 필요 가 없 으 며,이러한 서 비 스 는 아주 짧 은 생존 기간 만 있다 는 것 을 알 고 있 습 니 다.
  • 조심스럽게 사용 Scoped 유형 서비스 라 이 프 사이클 은 하위 서비스 역할 영역 을 만 들 거나 비 웹 프로그램 에서 이 서 비 스 를 사용 하면 기괴 하고 복잡 해 지기 때문이다.
  • Singleton 사용 조심 다 중 스 레 드 문제 와 잠재 적 인 메모리 누 출 문 제 를 처리 해 야 하기 때문에 유형의 수명 주기 입 니 다.
  • Singleton 서비스 에 의존 하지 마 세 요. Transient 타 입 이나 Scoped 타 입의 서비스.단일 서비스 가 주입 되면 Transient 서비스 도 하나의 인 스 턴 스 가 되 기 때문이다.또한 Transient 서비스 가 이러한 장면 을 지원 하 는 디자인 이 아니라면 문제 가 생 길 수 있 습 니 다.ASP.NET Core 의 기본 DI 용 기 는 이 경우 이상 을 던 집 니 다.

  • 방법 체 에서 서 비 스 를 분석 하 다.
    어떤 경우 에는 서비스의 어떤 방법 에서 다른 서 비 스 를 분석 해 야 할 수도 있 습 니 다.이 경우 사용 후 이 서 비 스 를 풀 어 주 십시오.이것 을 보장 하 는 가장 좋 은 방법 은 서비스 역할 영역 을 만 드 는 것 이다.예 를 들 면:
      public class PriceCalculator
      {
          private readonly IServiceProvider _serviceProvider;
          public PriceCalculator(IServiceProvider serviceProvider)
          {
              _serviceProvider = serviceProvider;
          }
          public float Calculate(Product product, int count,
            Type taxStrategyServiceType)
         {
             using (var scope = _serviceProvider.CreateScope())
             {
                 var taxStrategy = (ITaxStrategy)scope.ServiceProvider
                   .GetRequiredService(taxStrategyServiceType);
                 var price = product.Price * count;
                 return price + taxStrategy.CalculateTax(price);
             }
         }
     }
    

    PriceCalculator 는 구조 함수 에 IServiceProvider 를 주입 하고 필드 에 값 을 부여 합 니 다.그리고 PriceCalculator 는 Calculate 방법 내부 에 하위 서비스 역할 영역 을 만 들 었 습 니 다.이 역할 영역 사용 scope.Service Provider 는 주입 한 대신 서 비 스 를 분석 합 니 다.serviceProvider 인 스 턴 스.따라서 using 구문 이 끝나 면 이 역할 영역 에서 분 석 된 모든 서 비 스 는 자동 으로 방출 되 고 소각 된다.
    실천 지침:
  • 만약 에 특정한 방법 에서 서 비 스 를 분석 하면 서브 서비스 역할 도 메 인 을 만들어 서 분 석 된 서비스 가 정확하게 방출 되도록 확보한다.

  • 하면,만약,만약... IServiceProvider 는 매개 변수 로 서 서 서 비 스 를 직접 분석 할 수 있 으 며 서비스의 방출 과 소각 에 관심 을 가 질 필요 가 없습니다.서비스 역할 영역 을 만 들 고 관리 하 는 것 은 방법 을 호출 하 는 코드 의 역할 입 니 다.이 원칙 을 따 르 면 너의 코드 를 더욱 깨끗하게 할 수 있다.
  • 분 석 된 서비스 가 인용 되 지 않도록 하 세 요!그렇지 않 으 면 메모리 누 출 을 초래 할 수 있다.그리고 뒤에서 대상 을 인용 할 때 삭 제 된 서비스 에 접근 할 수 있 습 니 다.(해 석 된 서비스 가 단일 사례 가 아 닌 경우)
  • 싱글 턴 서비스
    단일 서 비 스 는 일반적으로 응용 프로그램의 상 태 를 유지 하 는 데 사용 된다.캐 시 는 응용 프로그램 상태의 좋 은 예 입 니 다.예 를 들 면:
      public class FileService
      {
          private readonly ConcurrentDictionary _cache;
          public FileService()
          {
              _cache = new ConcurrentDictionary();
          }
          public byte[] GetFileContent(string filePath)
          {
             return _cache.GetOrAdd(filePath, _ =>
             {
                 return File.ReadAllBytes(filePath);
             });
         }
     }

    FileService 는 디스크 읽 기 를 줄 이기 위해 파일 내용 을 간단하게 캐 시 했 습 니 다.이 서 비 스 는 하나의 예 로 등록 되 어야 합 니 다.그렇지 않 으 면 캐 시가 예상 한 대로 작 동 하지 않 을 것 입 니 다.
    실천 지침:
  • 서비스 가 상 태 를 가지 고 있다 면 스 레 드 안전 방식 으로 이 상 태 를 방문 해 야 합 니 다.모든 요청 이 이 서비스의 같은 인 스 턴 스 를 동시에 사용 하기 때문이다.사용 하 다 ConcurrentDictionary Dictionary 대신 스 레 드 안전 을 확보 합 니 다.
  • 은 단일 서비스 에서 Transient 또는 Scoped 서 비 스 를 사용 하지 마 십시오.Transient 서 비 스 는 스 레 드 안전 으로 설계 되 지 않 았 을 수도 있 기 때문이다.만약 에 이 서 비 스 를 사용 했다 면 이 서 비 스 를 사용 하 는 동안 다 중 스 레 드 문 제 를 처리 해 야 합 니 다(인 스 턴 스 에 lock 문 구 를 사용 합 니 다)
  • 메모리 누 출 은 보통 단일 서비스 로 인해 발생 한다.응용 프로그램 이 끝 날 때 까지 단일 서 비 스 는 방출 되 거나 소각 되 지 않 습 니 다.따라서 이러한 단일 서비스 가 클래스(또는 주입)를 예화 하 였 으 나 방출/소각 되 지 않 으 면 프로그램 이 끝 날 때 까지 메모리 에 남아 있 습 니 다.이러한 종류의 적시에 방출/소각 을 확보 하 다.위의'방법 체 에서 서 비 스 를 해석 합 니 다'의 장 을 보십시오.
  • 캐 시 데이터(이 사례 의 파일 내용)가 원본 데이터 원본 에 변화 가 생 겼 을 때 캐 시 데 이 터 를 업데이트/실효 하 는 시스템 을 만들어 야 합 니 다.

  • Scoped 서비스
    Scoped 라 이 프 사이클 의 서 비 스 는 모든 웹 요청 데 이 터 를 저장 하 는 좋 은 방법 으로 보 입 니 다.ASP.NET Core 는 모든 웹 에 서비스 역할 영역 을 만 들 기 를 요청 하기 때 문 입 니 다.따라서 서 비 스 를 Scoped 로 등록 하면 웹 요청 기간 에 공유 할 수 있 습 니 다.예 를 들 면:
      public class RequestItemsService
      {
          private readonly Dictionary _items;
      
          public RequestItemsService()
          {
              _items = new Dictionary();
          }  
         public void Set(string name, object value)
         {
             _items[name] = value;
         }
     
         public object Get(string name)
         {
             return _items[name];
         }
     }

    Requestitems 서 비 스 를 Scoped 로 등록 하고 서로 다른 서비스 에 주입 하면 다른 서비스 에서 추 가 된 항목 을 얻 을 수 있 습 니 다.같은 RequestItems Service 의 인 스 턴 스 를 공유 하기 때 문 입 니 다.이것 이 바로 우리 가 Scoped 서비스 에 대한 기대 이다.
     
    하지만!!!사실 이 항상 그런 것 은 아니다. 하위 서비스 역할 도 메 인 을 만 들 고 하위 역할 도 메 인 에서 RequestItems 서 비 스 를 분석 하면 RequestItems Service 의 새로운 인 스 턴 스 를 얻 을 수 있 으 며 원 하 는 대로 작업 하지 않 습 니 다.따라서 Scoped 서 비 스 는 항상 모든 웹 이 하나의 인 스 턴 스 를 요청 하 는 것 을 의미 하 는 것 은 아니다.
    당신 은 이렇게 뚜렷 한 실 수 를 하지 않 을 것 이 라 고 생각 할 수 있 습 니 다.그러나 이것 은 잘못 이 아니 라 상황 이 이렇게 간단 하지 않 을 수도 있다.만약 당신 의 서비스 간 에 큰 의존 관계 가 있다 면,당신 은 누군가가 하위 역할 영역 을 만 들 고 다른 주 입 된 서비스 에서 서 비 스 를 분 석 했 는 지 모 르 겠 습 니 다....................................................
    실천 지침:
  • Scoped 서 비 스 는 웹 요청 에 너무 많은 서 비 스 를 주입 하 는 최적화 라 고 볼 수 있다.따라서 같은 웹 요청 기간 에 모든 서 비 스 는 이 서비스의 단일 인 스 턴 스 를 사용 합 니 다.
  • Scoped 서 비 스 는 스 레 드 안전 으로 설계 할 필요 가 없습니다.하나의 웹 요청 이나 스 레 드 에 정상적으로 사용 되 어야 하기 때문이다.그러나 이런 상황 에서 서로 다른 라인 사이 에서 서비스 역할 영역 을 공유 해 서 는 안 된다.
  • 웹 요청 에서 Scoped 서 비 스 를 설계 하여 다른 서비스 간 에 데 이 터 를 공유 하려 면 조심 하 십시오.HttpContext 에 모든 웹 이 요청 한 데 이 터 를 저장 할 수 있 습 니 다.(IHttpContextAccessor 를 주입 하여 방문 하여 물 어 볼 수 있 습 니 다)이것 은 데 이 터 를 공유 하 는 더욱 안전 한 방식 입 니 다.HttpContext 의 생명 주 기 는 Scoped 타 입 이 아 닙 니 다.사실상 DI 에 등록 되 지 않 습 니 다.(이것 도 왜 주입 하지 않 고 IHttpContextAccessor 를 주입 하여 대체 합 니까?)HttpContextAccessor 채택 AsyncLocal 은 웹 요청 기간 에 같은 HttpContext 를 공유 합 니 다.
  • 결론:
    주입 에 의존 하 는 것 은 처음에는 사용 하기 쉬 워 보이 지만 엄격 한 원칙 을 따 르 지 않 으 면 잠재 적 인 다 중 스 레 드 문제 와 메모리 누 출 문제 가 있 을 수 있다.내 가 공유 하 는 이 실천 지침 들 은 내 가 ABP 프레임 워 크 를 개발 하 는 동안 의 개인 적 인 경험 을 바탕 으로 한다.

    좋은 웹페이지 즐겨찾기