2013-07-28 4 views
1

Ninject에서 Simple Injector로 이동하려고하는데 Ninject와 함께 작동하는 기능을 복제하려고 할 때 이상한 문제가 발생합니다.간단한 인젝터 FilterInjection가 reinitialising 것으로 보인다 RegisterPerWebRequest는 아이템을 내 웠습니다.

private readonly ICollection<Message> messages; 

이 서비스는이 서비스는 메시지를 허용 (UI 및 오류) 다시 MVC 사이트에 전달되는

Bind<INotificationService>().To<NotificationService>() 
    .InRequestScope(); 

으로 등록 :

는 Ninject에 나는 포함 된 서비스를했다.

kernel.BindFilter<CriticalErrorAttribute>(FilterScope.Last, 1) 
    .When((context, ad) => 
     !string.IsNullOrEmpty(ad.ActionName) && 
     ad.ControllerDescriptor.ControllerName.ToLower() != "navigation"); 

및 OnActionExecuted 내에 사용 :

이 서비스는 ActionFilterAttribute 주입 하였다.

서비스가 InRequestScope로 Ninject에 등록되었으므로 메시지 대기열로 푸시 된 항목을 Actionfiter에서 사용할 수있었습니다. 이로 인해 필요한 경우 오류 페이지로 리다이렉트 (치명적 오류 표시) 할 수있었습니다. 메시지 모음 전에 ActionFilter를 입력하는 메시지가 포함하더라도

container.RegisterPerWebRequest<INotificationService, NotificationService>(); 

container.RegisterInitializer<CriticalErrorAttribute>(handler => 
{ 
    handler.NotificationService = 
     container.GetInstance<INotificationService>(); 
}); 

주입,하지만, 한 번 필터에 메시지 컬렉션 빈 괜찮 노력하고 있습니다 :

나는 simpleinjector와이를 복제하려고했습니다 . RegisterPerWebRequest가 무시되는 것과 같습니다.

이 문제를 해결하는 데 도움을 주시면 감사하겠습니다.

답변

3

UPDATE : 간단한 인젝터 2.5 새로운 RegisterMvcIntegratedFilterProvider 확장 방법에

이전 RegisterMvcAttributeFilterProvider 대체 MVC 통합 패키지에 추가되고 있습니다. 이 새로운 RegisterMvcIntegratedFilterProvider에는 아래에 주어진 SimpleInjectorFilterAttributeFilterProvider의 동작이 포함되어 있으며 단순 주입기 파이프 라인에 특성을보다 잘 통합 할 수 있습니다. 그러나 기본적으로 속성이 주입되지는 않지만 custom IPropertySelectionBehavior을 구현하면 확장 할 수 있습니다. 새 RegisterMvcIntegratedFilterProvider의 사용은 이전 RegisterMvcAttributeFilterProvider 메서드를 통해 진행되며 이후 릴리스에서는 [Obsolete]으로 표시됩니다. MVC 속성에


RegisterMvcAttributeFilterProvider 확장 방법을 사용하여

는 간단한 인젝터는 등록 초기화를 호출하지 않습니다. NotificationService을 삽입하는 익명의 대리자 안에 중단 점을 설정하면 절대 적중하지 않는 것을 볼 수 있습니다. 그러나 InjectProperties은 암시 적 속성 삽입을 수행합니다. 즉, 모든 공용 속성을 유형에 주입하려고 시도하지만 해당 속성을 삽입 할 수없는 경우 건너 뜁니다. (for 무슨 이유가 있었는지).

나는 대신 CriticalErrorAttribute.NotificationService 속성의 유형이 NotificationService 일 것입니다.NotificationService을 명시 적으로 등록하지 않았기 때문에 컨테이너가 사용자 대신 임시 인스턴스를 생성하므로 나머지 응용 프로그램보다 많은 CriticalErrorAttribute 인스턴스가 생성됩니다.

빠른 수정 : 속성 유형을 INotificationService으로 변경하십시오.

사실, 단순 주입기의 MVC 통합 패키지를 구현하여 InjectProperties 메소드를 사용하는 것은 유감 스럽습니다. Implicit Property injection은 잘못된 설정이있을 때 빠르게 실패하지 않고 나중에 InjectProperties에 대한 지원을 제거 할 생각이기 때문에 매우 나쁜 것입니다. 문제는 많은 개발자가 InjectProperties에 의존한다는 것입니다. 직접 호출하거나 컨테이너가 MVC 속성에 속성을 주입하도록함으로써 간접적으로 호출합니다.

InjectProperties 초기화 도구가 실행되지 않습니다. 그게 의도적인데 컨테이너에 의해 생성되지 않은 객체에 대해 전체 초기화 프로세스를 실행할 수있는 다른 구조가 있습니다. 그러나이 문제를 추가하면 기존 클라이언트가 손상 될 수 있습니다. 이로 인해 속성이 여러 번 주입 될 수 있습니다. 응용 프로그램의 시작 경로에 container.RegisterMvcAttributeFilterProvider()를 호출

방지 : 귀하의 경우

, 나는 다른 해결책을 제안한다. 내부적으로 InjectProperties을 호출하는 FilterAttributeFilterProvider 특수 문자가 등록됩니다. 암시 적 속성 주입을 사용하지 않으려는 경우보다 명확한 (그리고 완전한) 동작이 필요합니다.

internal sealed class SimpleInjectorFilterAttributeFilterProvider 
    : FilterAttributeFilterProvider 
{ 
    private readonly ConcurrentDictionary<Type, Registration> registrations = 
     new ConcurrentDictionary<Type, Registration>(); 

    private readonly Func<Type, Registration> registrationFactory; 

    public SimpleInjectorFilterAttributeFilterProvider(Container container) 
     : base(false) 
    { 
     this.registrationFactory = type => 
      Lifestyle.Transient.CreateRegistration(type, container); 
    } 

    public override IEnumerable<Filter> GetFilters(
     ControllerContext context, 
     ActionDescriptor descriptor) 
    { 
     var filters = base.GetFilters(context, descriptor).ToArray(); 

     foreach (var filter in filters) 
     { 
      object instance = filter.Instance; 

      var registration = registrations.GetOrAdd(
       instance.GetType(), this.registrationFactory); 

      registration.InitializeInstance(instance);     
     } 

     return filters; 
    } 
} 

당신이 사용자 지정 공급자를 등록하려면 다음 코드를 사용할 수 있습니다 : 다음 Registration.InitializeInstance 메소드를 호출 SimpleInjectorFilterAttributeFilterProvider

var filterProvider = 
    new SimpleInjectorFilterAttributeFilterProvider(container); 

container.RegisterSingle<IFilterProvider>(filterProvider); 

var providers = FilterProviders.Providers 
    .OfType<FilterAttributeFilterProvider>().ToList(); 

providers.ForEach(provider => FilterProviders.Providers.Remove(provider)); 

FilterProviders.Providers.Add(filterProvider); 

이 사용자 대신 다음 클래스를 등록합니다. 이 메서드는 이미 초기화 된 형식을 초기화 할 수 있으며 형식 이니셜 라이저 대리자를 호출하여 초기화합니다.

속성 작업에 대한 자세한 내용은 following discussion을 참조하십시오.

+1

사용자 지정 IPropertySelectionBehavior를 구현하여 Simple Injector가 특성에 특성을 강제로 주입하도록 할 수도 있습니다. 이렇게하면 사용자 정의 초기화 프로그램을 작성할 필요가 없습니다. 가능한 경우 명시 적으로 속성을 등록하십시오. 이 방법은 그것들을 검증 할 수 있습니다. – Steven

+0

'FilterProviders.Providers.Add (filterProvider);'가되어야합니까? – ajbeaven

+1

@ajbeaven : 고마워요. 더 이상 쓸모없는 SimpleInjectorFilterAttributeFilterProvider에서 더 중요한 버그를 수정했습니다. – Steven