2016-10-01 1 views
2

IOC 컨테이너를 사용하는 데있어 아직 조금 익숙하며 조금 어려움을 겪고 있습니다. ASP.NET MVC 5.2 Ninject.MVC3 함께 사용하고 있습니다. 기본적으로 로그 서비스에 넘겨주는 예외 필터가 있습니다.ASP.NET MVC의 RegisterGlobalFilters 메서드 내에서 종속성 삽입 수행 방법

public class ExceptionLoggerFilter : IExceptionFilter 
{ 
    private readonly ILogService _logService; 

    public ExceptionLoggerFilter(ILogService logService) { 
     _logService = logService; 
    } 

    public void OnException(ExceptionContext filterContext) { 
     _logService.LogError(filterContext.Exception); 
    } 
} 

로그 서비스 인스턴스를 가져 오기 위해 종속성 삽입을 사용하고 싶습니다. 그러나, RegisterGlobalFilters 방법은 정적 :

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new ExceptionLoggerFilter(???)); 
    } 
} 

나는 FilterConfig에 대한 정적 생성자를 사용할 수 있지만 이것은 단지 좋은 해결책처럼 생각하지 않습니다.

나는 ExceptionLoggerFilter 클래스에 속성 주입을 사용했지만, 그냥 작동하지 않았다 (LogService는 항상 null입니다) :

[Inject] 
public ILogService LogService { get; set; } 

나는 공장 패턴을 사용하여 읽어했지만, 그렇지 않은 Factory 클래스를 FilterConfig 클래스의 정적 생성자에 삽입해야하므로 여기서 도움이되는 것 같습니다. 나는 틀릴 수도 있지만 이것은 올바른 해결책 인 것 같지 않습니다.

지금, 나는이 사용하고 단지 - 줄 - 나-AN-인스턴스 방법 :

var logService = (ILogService)DependencyResolver.Current.GetService(typeof(ILogService)); 
filters.Add(new ExceptionLoggerFilter(logService)); 

이 작동하지만, 좋은 솔루션입니다? 더 좋은 방법이 있습니까? 의존성 주입에 대한 제 생각과 IOC 컨테이너가 엉망입니다.

답변

0

먼저 IExceptionFilterExceptionLoggerFilter 유형을 등록해야합니다.
그리고 다음과 같은 추가 :

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     var logger = DependencyResolver.Current.GetService<IExceptionFilter>(); 
     filters.Add(logger); 
    } 
} 
+2

'IExceptionFilter'등록 (및 모든 해당 종속성)이 확실하지 않은 경우에는 일반적으로 잘못된 생각입니다. ar e 싱글 톤은 MVC 전역 필터가 전역 적으로 저장되므로 싱글 톤이된다는 의미입니다. – Steven

3

MVC 글로벌 필터 인스턴스 단지 목록입니다. 즉, 필터와 같은 종속성도 싱글 톤이됩니다. 이것은 응용 프로그램에서 우연히 실수로 Captive Dependency이 발생하기 쉽기 때문에이 접근법에 매우주의해야한다는 것을 의미합니다. Captive Dependencies는 흔히 추적하기가 어렵고 종종 테스트 또는 생산에서만 나타납니다.

대신 필터를 사용할 때 컨테이너/커널로 다시 위임 할 수있는 프록시 클래스를 만들어 현장에서 실제 필터를 해결할 수 있습니다. 이렇게하면 종속 종속성이 방지됩니다. 로 볼 수

이러한 프록시는 다음과 다음과 같이

public class NinjectExceptionFilterProxy<TExceptionFilter> : IExceptionFilter 
    where TExceptionFilter : IExceptionFilter 
{ 
    private readonly Kernel _kernel; 

    public ExceptionLoggerFilter(Kernel kernel) { 
     _kernel = kernel; 
    } 

    public void OnException(ExceptionContext filterContext) { 
     var filter = _kernel.Get<TExceptionFilter>(); 
     filter.OnException(filterContext); 
    } 
} 

당신은 프록시 필터를 등록 할 수 있습니다

public static void RegisterGlobalFilters(GlobalFilterCollection filters, IKernel kernel) 
{ 
    filters.Add(new NinjectExceptionFilterProxy<ExceptionLoggerFilter>(kernel)); 
} 
0
당신은 사용자 정의 필터 제공자를 구축하여 그것이 당신이 가로 챌 수 있다고 할 수

필터가 생성되는 프로세스이며이 단계에서 종속성을 주입 할 수 있습니다.다음은

쉽게 새로운 필터를 사용

public class UnityActionFilterProvider : FilterAttributeFilterProvider 
{ 
    private readonly IUnityContainer container; 

    public UnityActionFilterProvider(IUnityContainer container) 
    { 
     this.container = container; 
    } 


    public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     var filters = base.GetFilters(controllerContext, actionDescriptor); 

     foreach (var filter in filters) 
     { 
      container.BuildUp(filter.Instance.GetType(), filter.Instance); 
     } 

     return filters; 
    } 
} 

다음, FilterConfig.cs에서, 업데이트 RegisterGlobalFilters

Ninject에

로 변환 필터 공급자의 클래스를 만들 수 있습니다, 유니티와 샘플입니다 제공자

public class FilterConfig 
    { 
     public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
     { 
      var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider); 
      FilterProviders.Providers.Remove(oldProvider); 

      var container = UnityConfig.GetConfiguredContainer(); 
      var provider = new UnityActionFilterProvider(container); 
      FilterProviders.Providers.Add(provider); 

      filters.Add(new HandleErrorAttribute()); 
     } 
    } 
관련 문제