2017-12-16 25 views
2

HttpContext.RequestServices 또는 IServiceProvider을 통해 서비스를 요청하는 것이 나쁜 습관을 고려하는 이유는 무엇입니까? 나는 사방이 문장을 읽을 수 있습니다 : 그것을 사용 RequestServices을 얻는 대신 생성자 주입을 사용하는 것이 좋습니다ASP.NET Core DI 생성자 대 RequestServices

.


내 생각은 반대입니다. 가능하면 RequestServices를 사용하십시오. 이유를 설명해 드리겠습니다. 별도의 서비스를 만들기 위해 가능한 한 컨트롤러를 작게 유지하고 싶습니다. 이렇게하면 내 컨트롤러는 깨끗합니다.

public class MyController : Controller 
{ 
    public MyController(IMyServices MyServices){} 

    public async Task<IActionResult> GetSomething(int parameter) 
    { 
     return await this.MyServices.SomeMethod(parameter); 
    } 
} 

모든 서비스는 권한 관리 논리를 포함하는 base에서 sql 요청을 캐싱합니다. 생성자에

public class MyBaseService 
{ 
    public MyBaseService(ILogger Logger, AppDbContext Context, IMemoryCache Cache) { } 

    public bool HasRight(string right) { return true; } 

    public bool IsLoggedIn() { return true; } 
} 

public class MyServices : MyBaseService 
{ 
    public MyServices(ILogger Logger, AppDbContext Context, IMemoryCache Cache) : base(Logger, Context, Cache) 
    {  
    } 
} 

하지만 GetRequiredService와 내가 호출을 단순화베이스 : 생성자 방식으로
나는 전화 기반의 매우 복잡한 시스템을 얻을

예, BaseService 더 많은 코드를 포함하지만 추가해야 할 때

public class MyBaseService2 
{ 
    private ServiceProvider _ServiceProvider; 
    public MyBaseService2(IServiceProvider ServiceProvider) 
    { 

    } 

    protected ILogger Logger { get { return this._ServiceProvider.GetRequiredService<ILogger>(); } } 

    protected AppDbContext Context { get { return this._ServiceProvider.GetRequiredService<AppDbContext>(); } } 

    protected IMemoryCache Cache { get { return this._ServiceProvider.GetRequiredService<IMemoryCache>(); } } 

    public bool HasRight(string right) { return true; } 

    public bool IsLoggedIn() { return true; } 
} 

public class MyServices2 : MyBaseService2 
{ 
    public MyServices2(IServiceProvider ServiceProvider) : base(ServiceProvider) 
    {  
    } 
} 
BaseService의 서비스를 사용하면 모든 클래스 기본 생성자 호출을 수정할 필요가 없습니다. 또한 모든 서비스에는 훨씬 간단한 생성자 (단지 IServiceProvider)가 있습니다.

만약 내가 생성자 접근에 반대한다면. 수명이 Scoped 인 경우 MyServices에 ServiceProvider.GetRequiredService을 호출하면 성능이 저하됩니까?

답변

3

HttpContext.RequestServices 또는 IServiceProvider를 통해 서비스를 요청하는 것이 나쁜 습관을 고려하는 이유는 무엇입니까?

Service Locator anti-pattern의 구현이므로 잘못된 방법으로 간주됩니다.

당신은 기본 클래스에 많은 일반적인 종속성과 공통의 논리를 이동하여 작은 컨트롤러 클래스를 유지하기 위해 노력하고 있지만이 자체 안티 패턴 이유는 종속성에서 해결 되더라도

  • 기본 클래스 인 경우 해당 종속성은 여전히 ​​숨겨져 있습니다 (this article 설명). 즉, 단위 테스트 및 DI 컨테이너에서 종속성을 숨 깁니다. 그러면 개체 그래프에서 분석을 수행 할 수 없게됩니다.
  • 기본 클래스가 항상 이고 그 파생어가과 강하게 결합되어 있기 때문에 기본 클래스에 대한 종속성을 이동해도 클래스의 복잡성은 줄어들지 않습니다.
  • 많은 책임이 기본 클래스에 포함되어 기본 클래스가 Single Responsibility Principle을 위반하게됩니다. 이것은 기본 클래스가 god 클래스가되고 지속적으로 변경되도록합니다.

기본 클래스는 상속을 사용하지만 소프트웨어 개발에 대한 일반적인 합의는 사용자가 Composition over inheritance을 선호해야한다는 것입니다.

구성을 선호해야하므로 종속성 삽입이 자동으로 이루어집니다. 기본 클래스가 없으면 생성자가 더 많은 인수를 갖기 때문에 즉시 Single Responsibility Principle 위반을 찾아내는 것이 더 쉬워집니다. 의존성의 수는 Service Locator를 사용할 때 변경되지 않는다는 것을 다시 한번 생각해보십시오.

생성자 삽입이 Constructor over-injection으로 쉽게 이어지는 사실을 받아 들여야합니다. 이는 이것이 우리 클래스가 너무 많음을 나타내며 그러한 클래스를 재 설계해야한다는 신호이기 때문입니다.

기본 클래스에서 로깅, 캐싱 및 권한 부여와 같은 cross-cutting concerns을 구현하는 대신 컴포지션을 사용하여 구현하십시오. 예를 들어, middleware, decorators 또는 interceptors을 사용하여 요청 (또는 요청의 특정 서비스)에 교차 절단 문제를 적용 할 수 있습니다.

+0

내가 중복 된 질문을 놓치는 이유를 모르지만 나는 기쁘다. 이것은 최고의 대답입니다. – Makla