2013-04-30 60 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