5

Używam Ninject i rozszerzeń EventBroker i DependencyCreation w aplikacji MVC 3. Zainstalowałem i używam pakietu Ninject.MVC3, a zatem OnePerRequestModule.Ninject - Zakres żądania został już usunięty

Próbuję wprowadzić usługę do kontrolera o nazwie IParentService. IParentService ma zależność od ChildService utworzoną przez rozszerzenie DependencyCreation (brak twardego odwołania).

Obie usługi są zarejestrowane w lokalnej instancji brokera zdarzeń (lokalne dla ParentService).

chcę IParentService być zakrojony na życzenie i chcę zależność i broker wydarzenie być usuwane w tym samym czasie co IParentService jednak Dostaję ScopeDisposedException. Co robię źle?

Niektóre kodu:

serwisowe Definicje:

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) 
    {    
    } 
} 

Kernel rejestracja (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");    
    } 

Ślad stosu:

[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 

EDIT - Więcej Szczegółów

Błąd jest generowany wewnątrz delegata dezaktywacji, który jest ustawiony w zaproszeniu do RegisterOnEventBroker, gdzie kod usiłuje wyrejestrować żadnych przedmiotów zarejestrowane na maklera zdarzeń. Nie powiedzie się, ponieważ zakres brokera zdarzeń został usunięty, prawdopodobnie dlatego, że usługa nadrzędna została usunięta. O ile mi wiadomo, Ninject będzie wywoływał delegatów OnDeaktywacji tylko dla obiektów z czasem życia innym niż Transient, więc dlaczego to nie zadziała, kiedy usługa nadrzędna jest zarejestrowana w RequestScope, wprowadza mnie w błąd. Zakres przejściowy jest niewystarczający dla usługi nadrzędnej, ponieważ mam wycieki pamięci z powodu tego problemu.

Zaczynam się zastanawiać, czy jest to błąd w rozszerzeniu EventBroker.

Odpowiedz

2

Najpierw należy związać IParentService z ParentService, a następnie użyć samodzielnego wiązania betonu typu kernel.Bind<ParentService>().ToSelf(), aby zdefiniować zakres obiektu i broker zdarzeń.

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"); 
    }  

Zmieniano: jeśli typ jesteś rozwiązywania to rodzaj betonu (jak ParentService powyżej), Ninject automatycznie utworzy domyślny stowarzyszenie poprzez mechanizm zwany niejawna wiążące siebie. Jak to:

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

Z drugiej strony samorządów ukrytych powiązań są generowane w domyślnym obiektu zakresu, który jest Transient. Dlatego Twój kod nie działa w zakresie Request.

Więcej informacji można znaleźć w here

Pod 2:

jest błąd w bbvEventBroker rozszerzenia w Request zakresie które powodują EventBroker znajdowała się przed wyrzuceniem przedmiotu, który rejestruje w tym EventBroker. Dlatego w metodzie obiektu OnDeactivation nie ma EventBrokera, z którego można wyrejestrować jego Wyrejestrowanie i rzucenie wanemu.

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; 
    } 

można zobaczyć w OwnsEventBroker metody NamedScope określić zakres przedmiotu (ParentService), które egzekwowania go wyrzucać przed obiektem (ParentService).

Z drugiej strony w OnDeactivation obiektu (ParentService) istnieje potrzeba EventBroker, która została wcześniej usunięta.

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

Roztwór tworzenia drzewa obiektów z NamedScope. Zdefiniuj element macierzysty w zakresie Request, definiując dla swoich dzieci (Publisher/Subscriber) NamedScope i jest właścicielem brokera zdarzeń (OwnsEventBroker). Następnie zdefiniuj wydawca (ChildService1), a subskrybent (ChildService2) w nazwanym zakresie został zdefiniowany przez nadrzędnego. W ten sposób możesz upewnić się, że właściciel brokera zdarzeń zostanie usunięty po ich nadejściu.

+0

Dzięki Kambiz, to rozwiązuje problem. Czy możesz nieco więcej wyjaśnić, co było nie tak ze sposobem, w jaki to robiłem i dlaczego należy to zrobić w ten sposób? – nukefusion

+0

@nukefusion Zaktualizowałem odpowiedź, czekam na to –

+0

Podwajałem to sprawdzając, ale w moim teście wprowadzam IParentService, a nie konkretny typ. To wydawało się naprawić mój problem, ale w rzeczywistości było to po prostu używanie twojego pierwszego wiązania zamiast drugiego "self" wiązania. Jeśli użyję twojego kodu i wstrzyknę instancję "ParentService", otrzymam ten sam wyjątek. – nukefusion

2

Ninject core obecnie dezaktywuje obiekty znajdujące się w zasięgu obiektu przed dezaktywacją samego obiektu.

Zmiana zamówienia wydaje się rozwiązać ten problem. Chociaż przed wprowadzeniem tej zmiany muszę sprawdzić, jakie skutki uboczne mogą to mieć w innych sytuacjach.

+0

Dzięki za zaglądanie do tego Remo. Czy istnieje otwarty problem, aby można go było śledzić? – nukefusion