2013-04-30 27 views
5

ich Ninject bin mit und die Erweiterungen EventBroker und DependencyCreation in einer MVC-3-Anwendung. Ich habe installiert und verwende das Ninject.MVC3-Paket und daher die OnePerRequestModule.Ninject - Antrag Umfang bereits angeordnet worden

Ich bin versucht, einen Dienst zu injizieren, die so genannte IParentService in einen Controller. IParentService hat eine Abhängigkeit von ChildService erstellt über die DependencyCreation-Erweiterung (keine harte Referenz).

Beide Dienste sind auf einem lokalen Event-Broker-Instanz (lokal bis ParentService) registriert.

möchte ich die IParentService pro Antrag scoped werden, und ich möchte, dass die Abhängigkeit und Event-Broker der als IParentService jedoch zugleich angeordnet sein, ich bin ein ScopeDisposedException bekommen. Was mache ich falsch?

Einige Code:

Service-Definitionen:

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

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

Stapelüberwachung:

[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 - Mehr Details

Der Fehler innerhalb eines Deaktivierungs Delegat geworfen wird, die in dem Aufruf von RegisterOnEventBroker festgelegt ist, in dem der Code alle Objekte auf der Event-Makler registriert abzumelden versucht. Es schlägt fehl, da der Ereignisbrokerbereich entfernt wurde, vermutlich weil der übergeordnete Dienst entsorgt wurde. Soweit mir bekannt ist, wird Ninject OnDeactivation-Delegaten nur für Objekte mit anderen Lebensdauern als Transient aufrufen. Warum funktioniert das nicht, wenn der übergeordnete Dienst unter RequestScope confuses me registriert ist. Der transitorische Bereich reicht für den übergeordneten Service nicht aus, da aufgrund dieses Problems Speicherlecks auftreten. wenn dies ein Fehler in der EventBroker Erweiterung zu fragen, ist

Ich fange an.

Antwort

2

Sie müssen zuerst IParentService an ParentService binden und dann den Typ kernel.Bind<ParentService>().ToSelf() selbstbindend verwenden, um Objektbereich und Ereignisbroker zu definieren.

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

Edited: , wenn der Typ Sie lösen sind ein konkreter Typ (wie ParentService oben), Ninject eine Standardzuordnung über einen Mechanismus implizit selbst automatisch aufgerufen erstellen verbindlich. So:

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

Auf der anderen Seite impliziten Selbstbindungen werden im Standard Object Scope erzeugt, die Transient ist. Aus diesem Grund wird der Code nicht in Request Bereich ausgeführt.siehe

Weitere Informationen here

2 Herausgegeben:

Es ist ein Fehler in bbvEventBroker Erweiterung in Request Umfang die EventBroker verursachen angeordnet war, bevor der Gegenstand angeordnet wird, die an diesem EventBroker registriert. Daher gibt es in der OnDeactivation Methode des Objekts keinen EventBroker, dessen Unregister aufgerufen werden kann und ScopeDisposedException wan geworfen wird.

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

Sie können in OwnsEventBroker Verfahren sehen im Rahmen des Objekts (ParentService), die es vor dem Objekt (ParentService) Verfügungs erzwingen NamedScope zu definieren.

Auf der anderen Seite in des Objekts (ParentService) gibt es EventBroker, die früher entsorgt.

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

Die Lösung, die den Objektbaum mit NamedScope schafft. Definieren Sie übergeordnete Elemente in Request Bereich, während es ein NamedScope für seine untergeordneten Elemente (Publisher/Subscriber) definiert, und besitzt den Ereignisbroker (OwnsEventBroker). Definieren Sie dann einen Verleger (ChildService1) und einen Abonnenten (ChildService2) in dem benannten Bereich, der vom übergeordneten definiert wurde. Auf diese Weise können Sie sicherstellen, dass der Eigentümer des Ereignismaklers nach seinem Kind entsorgt wird.

+0

Danke Kambiz, das den Fehler auflöst. Kannst du ein bisschen mehr darüber erzählen, was mit der Art, wie ich es gemacht habe, falsch war und warum es so gemacht werden muss? – nukefusion

+0

@nukefusion Ich aktualisierte die Antwort überprüfen Sie es –

+0

Ich habe verdoppelt dies überprüft, aber in meinem Test Ich injiziere IParentService nicht den konkreten Typ. Dies schien mein Problem zu beheben, aber tatsächlich war es nur Ihre erste Bindung anstelle der zweiten "Selbstbindung". Wenn ich Ihren Code benutze und eine 'ParentService' Instanz injiziere, bekomme ich die selbe Ausnahme. – nukefusion

2

Der Ninject-Core deaktiviert derzeit Objekte, die sich im Bereich eines Objekts befinden, bevor das Objekt selbst deaktiviert wird.

Ändern der Reihenfolge scheint dieses Problem zu beheben. Aber bevor ich diese Änderung durchführe, muss ich prüfen, welche Nebenwirkungen dies für andere Situationen haben kann.

+0

Vielen Dank für den Blick in diese Remo. Gibt es ein offenes Problem dafür, damit ich es verfolgen kann? – nukefusion