5

MVC 3 응용 프로그램에서 Ninject 및 EventBroker 및 DependencyCreation 확장을 사용하고 있습니다. 설치하고 Ninject.MVC3 패키지를 사용하고 따라서 OnePerRequestModule.Ninject - 요청 범위가 이미 처리되었습니다.

컨트롤러에 IParentService이라는 서비스를 주입하려고합니다. IParentService은 DependencyCreation 확장 (하드 참조 없음)을 통해 생성 된 ChildService에 대한 종속성이 있습니다.

두 서비스는 로컬 이벤트 브로커 인스턴스 (로컬 ParentService)에 등록됩니다.

은 내가 IParentService이 요청에 따라 범위 싶은 나는 종속성 및 이벤트 브로커 그러나, 나는 ScopeDisposedException 받고 있어요는 IParentService과 동시에 폐기하고자합니다. 내가 뭘 잘못 했니?

일부 코드 :

서비스 정의 :

public interface IParentService 
{ 
} 

public class ParentService : IParentService 
{ 
    [EventPublication("topic://ParentService/MyEvent")] 
    public event EventHandler<EventArgs> MyEvent; 
} 

public class ChildService 
{ 
    [EventSubscription("topic://ParentService/MyEvent", typeof(bbv.Common.EventBroker.Handlers.Publisher))] 
    public void OnMyEvent(object sender, EventArgs eventArgs) 
    {    
    } 
} 

커널 등록 (NinjectWebCommon)

private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Bind<IParentService>().To<ParentService>() 
      .InRequestScope() 
      .OwnsEventBroker("ParentServiceBroker") 
      .RegisterOnEventBroker("ParentServiceBroker"); 

     kernel.DefineDependency<IParentService, ChildService>(); 
     kernel.Bind<ChildService>().ToSelf() 
      .WhenInjectedInto<ParentService>() 
      .InDependencyCreatorScope() 
      .RegisterOnEventBroker("ParentServiceBroker");    
    } 

스택 추적 :

,451,515,
[ScopeDisposedException: The requested scope has already been disposed.] 
    Ninject.Extensions.NamedScope.NamedScopeExtensionMethods.GetScope(IContext context, String scopeParameterName) in c:\Projects\Ninject\ninject.extensions.namedscope\src\Ninject.Extensions.NamedScope\NamedScopeExtensionMethods.cs:118 
    Ninject.Extensions.NamedScope.NamedScopeExtensionMethods.GetScope(IContext context, String scopeParameterName) in c:\Projects\Ninject\ninject.extensions.namedscope\src\Ninject.Extensions.NamedScope\NamedScopeExtensionMethods.cs:126 
    Ninject.Extensions.NamedScope.<>c__DisplayClass1`1.<InNamedScope>b__0(IContext context) in c:\Projects\Ninject\ninject.extensions.namedscope\src\Ninject.Extensions.NamedScope\NamedScopeExtensionMethods.cs:40 
    Ninject.Planning.Bindings.BindingConfiguration.GetScope(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\BindingConfiguration.cs:119 
    Ninject.Planning.Bindings.Binding.GetScope(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\Binding.cs:224 
    Ninject.Activation.Context.GetScope() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:123 
    Ninject.Activation.Caching.Cache.TryGet(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:110 
    Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:150 
    Ninject.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:386 
    System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +145 
    System.Linq.<CastIterator>d__b1`1.MoveNext() +85 
    System.Linq.Enumerable.Single(IEnumerable`1 source) +191 
    Ninject.ResolutionExtensions.Get(IResolutionRoot root, String name, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:50 
    Ninject.Extensions.ContextPreservation.ContextPreservationExtensionMethods.ContextPreservingGet(IContext context, String name, IParameter[] parameters) in c:\Projects\Ninject\ninject.extensions.contextpreservation\src\Ninject.Extensions.ContextPreservation\ContextPreservationExtensionMethods.cs:56 
    Ninject.Extensions.bbvEventBroker.<>c__DisplayClass2`1.<RegisterOnEventBroker>b__0(IContext ctx, T instance) in c:\Projects\Ninject\ninject.extensions.bbveventbroker\src\Ninject.Extensions.bbvEventBroker\EventBrokerExtensionMethods.cs:45 
    Ninject.Planning.Bindings.<>c__DisplayClass29`1.<OnDeactivation>b__28(IContext context, Object instance) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\BindingConfigurationBuilder.cs:513 
    Ninject.Activation.Strategies.<>c__DisplayClass4.<Deactivate>b__3(Action`2 action) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Strategies\BindingActionStrategy.cs:42 
    Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:32 
    Ninject.Activation.Strategies.BindingActionStrategy.Deactivate(IContext context, InstanceReference reference) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Strategies\BindingActionStrategy.cs:42 
    Ninject.Activation.<>c__DisplayClass6.<Deactivate>b__4(IActivationStrategy s) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Pipeline.cs:72 
    Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:32 
    Ninject.Activation.Pipeline.Deactivate(IContext context, InstanceReference reference) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Pipeline.cs:72 
    Ninject.Activation.Caching.Cache.Forget(CacheEntry entry) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:253 
    Ninject.Activation.Caching.Cache.Forget(IEnumerable`1 cacheEntries) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:242 
    Ninject.Activation.Caching.Cache.Clear(Object scope) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:197 
    Ninject.Web.Common.<>c__DisplayClass2.<DeactivateInstancesForCurrentHttpRequest>b__1(IKernel kernel) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\OnePerRequestHttpModule.cs:74 
    Ninject.GlobalKernelRegistration.MapKernels(Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\GlobalKernelRegistration.cs:75 
    Ninject.Web.Common.OnePerRequestHttpModule.DeactivateInstancesForCurrentHttpRequest() in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\OnePerRequestHttpModule.cs:74 
    Ninject.Web.Common.OnePerRequestHttpModule.<Init>b__0(Object o, EventArgs e) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\OnePerRequestHttpModule.cs:56 
    System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69 

편집 - 자세한 내용은 오류는 코드가 이벤트 브로커에 등록 된 물체의 등록을 취소하려고 시도 RegisterOnEventBroker에 호출에 설정되어있는 비활성화 위임 내에서 발생합니다

. 이벤트 브로커 범위가 삭제 되었기 때문에 실패합니다. 아마도 상위 서비스가 삭제 되었기 때문입니다. 내가 아는 한, Ninject는 Transient 범위 이외의 수명을 가진 객체에 대해서만 OnDeactivation 대리자를 호출하므로, 부모 서비스가 RequestScope에 등록되어있을 때 이것이 작동하지 않는 이유는 무엇입니까? 이 문제로 인해 메모리 누수가 발생하기 때문에 일시적 범위가 상위 서비스에 충분하지 않습니다.

이것이 EventBroker 확장의 버그인지 궁금해졌습니다.

답변

2

먼저 IParentServiceParentService으로 바인드하고 구체 유형 kernel.Bind<ParentService>().ToSelf()의 자체 바인딩을 사용하여 오브젝트 범위 및 이벤트 브로커를 정의해야합니다.

private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Bind<IParentService>().To<ParentService>(); 


     kernel.Bind<ParentService>().ToSelf() 
     .InRequestScope() 
     .OwnsEventBroker("ParentServiceBroker") 
     .RegisterOnEventBroker("ParentServiceBroker"); 

     kernel.DefineDependency<IParentService, ChildService>(); 
     kernel.Bind<ChildService>().ToSelf() 
      .WhenInjectedInto<ParentService>() 
      .InDependencyCreatorScope() 
      .RegisterOnEventBroker("ParentServiceBroker"); 
    }  

편집 : 당신이 해결하고있는 유형 (위 ParentService 같은) 구체적인 유형 인 경우 , Ninject에 자동으로 암시 적 자기 결합이라는 메커니즘을 통해 기본 연결을 만들 것입니다. 이처럼 : 다른 한편으로 암시 적 자기 바인딩에

kernel.Bind<ParentService>().ToSelf(); 

Transient 인 기본 개체의 범위에서 생성됩니다. 이것이 코드가 Request 범위에서 실행되지 않는 이유입니다.EventBroker 그 EventBroker에 등록 오브젝트의 배치 전에 배치 된 원인 Request 범위 bbvEventBroker 확장에 버그가

:

자세한 내용

here 2 편집 참조. 따라서 개체의 OnDeactivation 메서드에는 해당 Unregister를 호출 할 수있는 EventBroker가 없으며 ScopeDisposedException wan throw됩니다.

public static IBindingOnSyntax<T> OwnsEventBroker<T>(this IBindingOnSyntax<T> syntax, string eventBrokerName) 
    { 
     string namedScopeName = "EventBrokerScope" + eventBrokerName; 
     syntax.DefinesNamedScope(namedScopeName); 
     syntax.Kernel.Bind<IEventBroker>().To<EventBroker>().InNamedScope(namedScopeName).Named(eventBrokerName); 
     syntax.Kernel.Bind<IEventBroker>().ToMethod(ctx => ctx.ContextPreservingGet<IEventBroker>(eventBrokerName)).WhenTargetNamed(eventBrokerName); 
     return syntax; 
    } 

사용자는 개체 (ParentService) 앞에 배치하는 적용 대상 (ParentService)의 범위에 정의 NamedScope OwnsEventBroker 방법에서 볼 수있다.

한편 객체 (ParentService)의 OnDeactivation에는 이전에 배치 한 EventBroker가 필요합니다.

public static IBindingOnSyntax<T> RegisterOnEventBroker<T>(
     this IBindingOnSyntax<T> syntax, string eventBrokerName) 
    { 
     return 
      syntax.OnActivation((ctx, instance) => ctx.ContextPreservingGet<IEventBroker>(eventBrokerName).Register(instance)) 
        .OnDeactivation((ctx, instance) => ctx.ContextPreservingGet<IEventBroker>(eventBrokerName).Unregister(instance)); 
    } 

EventBrokerExtensionMethods.cs

이 솔루션은 NamedScope와 오브젝트 트리를 만드는 것입니다. 자식 (게시자/구독자)에 대해 NamedScope을 정의하고 이벤트 브로커 (OwnsEventBroker)를 소유하는 동안 Request 범위에 부모를 정의하십시오. 그런 다음 게시자 (ChildService1)를 정의하고 명명 된 범위에서 구독자 (ChildService2)를 부모가 정의했습니다. 이런 식으로 이벤트 중개인의 소유자가 자녀를 돌봐 줄 수 있습니다.

+0

감사합니다 Kambiz, 오류를 해결합니다. 제가하고있는 방식과 왜 잘못되었는지에 대해 좀 더 자세히 설명해 주시겠습니까? – nukefusion

+0

@nukefusion 나는 대답을 업데이트했습니다. –

+0

체크가 두 배로 늘었습니다. 그러나 테스트에서 IParentService를 구체적인 유형이 아닌 주입하고 있습니다. 이것은 내 문제를 해결하는 것으로 보였지만 실제로는 두 번째 '자체'바인딩 대신 첫 번째 바인딩을 사용하고있었습니다. 내가 당신의 코드를 사용하고 'ParentService'인스턴스를 삽입하면 같은 예외가 발생합니다. – nukefusion

2

Ninject 코어는 현재 개체 자체를 비활성화하기 전에 개체의 범위 내에있는 개체를 비활성화합니다.

주문을 변경하면 문제가 해결 된 것으로 보입니다. 그 변화를 추진하기 전에 다른 상황에 어떤 부작용이 있는지 확인할 필요가 있습니다.

+0

이 Remo를 찾아 주셔서 감사합니다. 이를 추적 할 수 있도록 공개 문제가 있습니까? – nukefusion

관련 문제