Ninject - 请求范围已经处理完毕

时间:2013-04-30 19:52:41

标签: c# asp.net-mvc ninject ninject.web.mvc ninject-extensions

我在MVC 3应用程序中使用Ninject和扩展EventBroker和DependencyCreation。我已安装并使用Ninject.MVC3包,因此使用OnePerRequestModule

我正在尝试将名为IParentService的服务注入控制器。 IParentService依赖于通过DependencyCreation扩展创建的ChildService(无硬引用)。

两个服务都在本地事件代理实例(ParentService的本地)上注册。

我希望每个请求都限定IParentService,我希望在IParentService的同时处理依赖项和事件代理,但是,我得到{{1} }}。 我做错了什么?

一些代码:

服务定义:

ScopeDisposedException

内核注册(NinjectWebCommon)

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

堆栈跟踪:

    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 的调用中设置的停用委托中抛出错误,其中代码尝试取消注册在事件代理上注册的任何对象。它失败是因为事件代理范围已被处理,可能是因为父服务已被处置。据我所知,Ninject只会为具有超出Transient范围的生命周期的对象调用OnDeactivation委托,所以当RegisterOnEventBroker中注册父服务时,为什么这不起作用。对于父服务而言,瞬态范围是不够的,因为我遇到了由于此问题导致的内存泄漏。

我开始怀疑这是否是EventBroker扩展中的错误。

2 个答案:

答案 0 :(得分: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方法中,没有EventBroker,可以调用其Unregister并抛出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)之前进行处置。

另一方面,对象(OnDeactivation)的ParentService需要事先处理过的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)由父级定义。通过这种方式,您可以确保事件经纪人的所有者将在他们的孩子之后被处置。

答案 1 :(得分:2)

在停用对象本身之前,Ninject核心当前会停用对象范围内的对象。

更改订单似乎解决了这个问题。虽然在推动这一改变之前,我必须检查这可能会对其他情况产生什么副作用。