ASP.NET Core의 IoC컨테이너, 서비스 로케이터 패턴 위반

요즘 Blazor 공부에 한창입니다.

첫번째 링크의 [Recommendations] 섹션과 두번째 링크의 [권장 사항] 섹션을 보시면 됩니다.
위 문서를 보면 종속성 주입에 대한 권장사항이 명시되어 있고 왜 권장사항인지는 나와있지 않습니다.

최근 Blazor를 공부하면서 아무래도 ASP.NET Core에서 IServiceCollection 을 통해 기본으로 IoC 컨테이너를 제공해주다보니 사용해보면서 이거 저거 찾아봤는데요.

아직 ViewModel의 생성자에 IoC 컨테이너에 등록한 타입의 파라미터를 받았을 때 어떤 원리로 ViewModel에 IoC컨테이너의 인스턴스가 주입되는지는 모르겠습니다.

또한 그렇게 생성자 주입을 통해 인스턴스를 주입받아 사용하는 것은 권장사항이나, 일반 메서드에서 IoC컨테이너에 등록된 서비스를 GetService를 통해 호출해서 사용하지 마라고 하네요.

그 이유가 무엇일까요?

좋아요 1

의미로 생각해보면 그 이유는 명확하다고 생각합니다.

[Inject] 속성 또는 생성자의 인자로 종속성 인스턴스를 주입하는 방식은 생성 시점입니다. 이후, 인스턴스가 생성된 이후부터는 그러한 종속 연결이 더이상 진행되지 않습니다. 즉, 종속 관점에서 생성 이후의 관계는 불변하게 됩니다. (생성자의 인자로 종속관계가 모두 드러납니다.)
불변하다는 것은 프로그래머가 인스턴스 생성 이후 종속관계를 추적할 필요가 없다는 것입니다.

그런데, GetService를 써서 일반 메소드에서 서비스 인스턴스를 받게 되면 종속 관계는 메소드를 호출할때와 호출하지 않을때 마다 변하게되므로 종속관계가 불명확해지게 됩니다. 이렇게 되면 문제가 발생했을 때 추적하기 어렵게 되고 다양한 버그가 생길 수 있습니다.

좋아요 2

안녕하세요?

제 개인적으로는 다음과 같은 이유가 있을 것 같습니다.

먼저
a. IoC 컨테이너에 등록한 타입의 파라미터를 받았을 때 어떤 원리로 ViewModel에 IoC컨테이너의 인스턴스가 주입되는지

=> 코어 서비스가 실행될때 HostBuilder가 같이 로드되는데요 이는 http서버가 요청을 처리할때 웹App의 수명을 처리하는데요 이때 등록한 서비스의 타입이 필요한지 여부에 따라 서비스 등록 환경설정을 보고 인스턴스를 자동으로 생성하고 DI시켜줍니다

b. 일반 메서드에서 IoC컨테이너에 등록된 서비스를 GetService를 통해 호출해서 사용하지 마라고 하네요.
그 이유가 무엇일까요?

=> DI를 통하지 않고 서비스를 직접 꺼내 사용할경우
DI전략과 싱글턴 또는 팩토리패턴 전략과 혼합해서 사용되기에 통일화 되지 않아 권장하지 않은 것 같습니다
이러한 경우 Setter Injection기반의 의존성 주입을 사용해서 처리하는게 맞을거 같습니다

좋아요 3

아하…느낌적인 느낌으로 그럴거 같았는데 역시 그랬군요. 답변 감사드립니다!!

a의 경우는 뭔가 코드로 그런 부분을 보고 싶었는데 그러려면 역시 ASP.NET Core의 오픈소스를 직접확인해야할 듯 하네요…
b 방법에 대한 부분은 구상이 잘 안되는군요…말씀하신 키워드로 검색해보겠습니다. 감사합니다!

제 생각에는… 몇가지로 추리자면 아래와 같습니다.

(이후 글부터 클래스를 컴포넌트로 지칭하겠습니다.)

  • 명시적 종속성 위반
    필요한 종속성을 캡슐화하는건 좋은 코드 디자인이 아닌거 같습니다. 컴포넌트는 자신이 운용되기 위해 필요한 종속성을
    직접적으로 요청해야합니다. 또한 그러한 종속성이 해결되지 않는다면 사용 할 수 없기에 생성자를 통한 주입이 일반적입니다.

  • 자동화 테스트의 어려움
    서비스 로케이터를 컴포넌트내에서 캡슐화해 사용한다면 외부에서 종속성을 어떻게 해결하는지 알 수 없습니다.
    즉, 자동화 테스트 작성을 위해 그 녀석이 필요로하는 환경 구성을 해줄 수 없습니다.

  • 종속성 변경에 대한 위험
    컴포넌트는 자신이 운용되기위해 필요한 종속성만을 요구하는게 좋을 것 같습니다.
    서비스 로케이터를 사용한다면… 무엇이든 해결할 수 있는 백도어를 열어준것과 같습니다.
    전지전능한 슈퍼맨을 얻은 효과죠. 유지관리 측면에서 코드는 보호되지 않을 확률이 높은거 같습니다.

(제 의견은 언제나 오답일 확률이 높습니다 ㅜㅜ)

좋아요 1

저도 마지막에 설명해주신 '서비스 로케이터를 사용한다면, 무엇이든 해결할 수 있는 백도어를 열어준 것과 같다’는 말에 공감합니다. 느낌적인 느낌으로 그거때문이려나 생각했지만 공식문서에서 이유를 안 적어주니 여러 의견을 듣고 싶었네요. 덕분에 생각이 견고해졌습니다. 감사합니다!!

좋아요 1