2013-04-30 77 views
5

我在使用Ninject以及MVC 3應用程序中的擴展EventBroker和DependencyCreation。我已安裝並正在使用Ninject.MVC3程序包,因此使用OnePerRequestModuleNinject - 請求範圍已被處置

我正在試圖注入一個服務,名爲IParentService到控制器。 IParentService對通過DependencyCreation擴展創建的​​有依賴關係(沒有硬引用)。

這兩種服務都在本地事件代理實例(本地ParentService)上註冊。

我想要IParentService作爲每個請求的作用域,我希望將依賴項和事件代理與IParentService同時處置,但是,我得到的是ScopeDisposedException我在做什麼錯?

某些代碼:

服務定義:

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

堆棧跟蹤:

[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只會調用OnDeactivation委託對象的生存時間以外的Transient作用域,所以當父服務註冊在RequestScope混淆我時,爲什麼這不起作用。由於此問題,我正在經歷內存泄漏,所以父服務的暫態範圍不足。

我開始懷疑這是否是EventBroker擴展中的錯誤。

回答

2

您必須先將IParentService綁定到ParentService,然後使用具體類型爲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範圍內運行。

有關詳細信息,請參閱here

編輯2:

有一個在bbvEventBroker延伸在Request範圍造成EventBroker被哪些寄存器上EventBroker對象的處理之前設置的錯誤。因此在該對象的OnDeactivation方法中沒有可以調用Unregister的EventBroker,並且拋出了ScopeDisposedException

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

可以在OwnsEventBroker方法參見NamedScope其​​中執行它的對象(ParentService)之前處理所述對象(ParentService)的範圍限定。

另一方面,在對象(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創建對象樹。在Request範圍內定義父項,同時爲子項(發佈者/訂閱者)定義NamedScope並擁有事件代理(OwnsEventBroker)。然後定義一個發佈者(ChildService1)和一個訂閱者(ChildService2)在父指定的範圍內。通過這種方式,您可以確保活動經紀人的所有者在他們的孩子後被處置。

+0

謝謝Kambiz,它確實解決了錯誤。你能詳細說明我做這件事的方式有什麼問題,以及爲什麼需要這樣做? – nukefusion 2013-05-09 08:22:29

+0

@nukefusion我更新了答案檢查它 – 2013-05-09 08:53:10

+0

我已經加倍檢查了這一點,但在我的測試中,我注射IParentService而不是具體類型。這似乎解決了我的問題,但實際上它只是使用您的第一個綁定而不是第二個「自我」綁定。如果我使用你的代碼並注入一個'ParentService'實例,我會得到相同的異常。 – nukefusion 2013-05-09 09:55:44

2

Ninject內核當前取消激活對象本身之前處於對象範圍內的對象。

更改順序似乎解決了這個問題。雖然在推動這個變化之前,我必須檢查這可能對其他情況有什麼副作用。

+0

感謝您查看此Remo。有沒有一個公開的問題,所以我可以跟蹤它? – nukefusion 2013-05-12 09:36:33