【问题标题】:Ninject InRequestScope fallback to InThreadScopeNinject InRequestScope 回退到 InThreadScope
【发布时间】:2011-10-31 09:35:22
【问题描述】:

在我的 MVC3 项目中,我已将我的内核设置为 NinjectInRequestScope 基础上的 Entityframework 上下文,这非常有效。但是我有一个后台运行程序,可以进行一些工作流管理。

它每 5 分钟启动一个新线程,我 Ninject 我的依赖项到这个线程中,如果我将范围更改为 InThreadScope,则 Dispose 方法会被触发,但如果我将其更改回InRequestScope Dispose 方法不会触发。

如果InRequestScope 不可用,有没有办法回退到InThreadScope

更新:刚刚对这个问题投了赞成票,为什么不更新一些额外的信息。我认为 Ninjects 处理生命周期的方式有点过时了。其他 IoC 的子容器是在整个子容器期间存在的瞬态注册对象,并在子容器存在时被释放。这是一种更简单的方法,例如将 Web API 与上述场景中的自定义工作器相结合。

【问题讨论】:

    标签: scope ninject


    【解决方案1】:

    有一个InScope 方法,您可以使用它指定自定义范围规则。

    InRequestScope 的实现目前正在从 2.2 到 2.4 进行更改。

    因此,转到您的版本源,查看 InRequestScopeInThreadScope 的 impl 并创建一个汞合金(然后您可以将其作为扩展方法与其他 InXXXScope 方法一起插入。

    它看起来(在您将其提取到扩展方法之前)类似于:

    Bind<X>.To<T>().InScope( ctx => ScopeContext.Request(ctx) ?? ScopeContext.Thread(ctx))
    

    另一种方法是创建两个Bindings,并带有适当的约束,例如WhenInjectedInto&lt;T&gt;,以根据contextual binding自定义范围。

    【讨论】:

    • 感谢您的快速回答,所以测试 InRequestScope 的唯一方法是 HttpContext.Current != null?如果可能的话,我想避免在我的 NinjectExtensionmethod 中使用 webreferences... Ninject 是否有一些帮助方法来确定 InRequstScope 是否可用?然后我可以做(伪代码).InScope(()=> InRequest()?StandardScopeCallbacks.Request:StandardScopeCallbacks.Thread)。我的 Ninject 绑定驻留在业务程序集中,我希望将 Web 程序集排除在外。
    • 如果你找到的助手不在请求中,它将返回 null,所以你不需要做你担心的条件位(因此我的 ?? 位让它通过)。
    • 接下来,Ninject 也不应该担心 Web(因此与 Web 相关的部分也将被拆分),并且 InRequestScope 还应该挂钩到 WCF OperationContext.Current。这些东西正在主干中进行,但 ninject 维护者。
    • 关于使它在您的上下文中工作的好方法...强烈建议获取 manning.com/seemann 并从头到尾阅读它 - 它没有涵盖有关 Ninject 的任何内容,但涵盖了 所有内容 关于 DI 架构。作为一个快速的答案,基于我对您的特定约束的有限知识并且没有做过很多类似的工作,我建议您在尝试更改默认范围时所做的诡计需要非常接近您的组合根- 业务组件不必担心托管它的多种方式。
    • Offcourse StandardScopeCallbacks.Request 只是 HttpContext.Current 的包装器:D 这很奇怪,如果我使用 InScope(() => StandardScopeCallbacks.Request) 它的行为与使用 .InRequestScope() 不同我使用 InRequestScope 它在请求结束后立即调用 dispoise 方法。使用 inscope,它根本不会调用 dispose 方法
    【解决方案2】:

    感谢鲁本,我找到了一个解决方案,但是在他的伪代码中潜入了一个小错误,由于是星期一,我很累,我没有马上看到它:D

    StandardScopeCallbacks.Request
    

    是代表并且

    StandardScopeCallbacks.Request ?? StandardScopeCallbacks.Thread 
    

    将始终返回左侧,因为委托永远不会为空。

    有两种正确的方法,

    1 扩展方法

    public static IBindingWhenInNamedWithOrOnSyntax<T> InRequestFallbackScope<T>(this IBindingWhenInNamedWithOrOnSyntax<T> binding)
    {
        Func<IContext, object> fallbackCallback = ctx => StandardScopeCallbacks.Request(ctx) ?? StandardScopeCallbacks.Thread(ctx);
        binding.Binding.ScopeCallback = fallbackCallback;
        return binding;
    }
    

    2 使用 InScope 方法

    .InScope(ctx => StandardScopeCallbacks.Request(ctx) ?? StandardScopeCallbacks.Thread(ctx))
    

    【讨论】:

    • 很好,被我的回答误导了。而且你必须喜欢fallbackCallback,所以+1。如果您想镀金,您可以将回调逻辑拉出到一个辅助类中,例如 la ninject - 这将表明扩展方法实际上与 InScope(x) 相同。 (如果你发现我的想法,我认为你可以将扩展名添加为binding.InScope( FallbackScopeCallbacks.RequestOrThread)
    【解决方案3】:

    这是我编写的,首先将请求范围和线程作为后备。

    public static class NinjectBindingExtensions
    {
        private static bool IsRequestPresent()
        {
            try
            {
                return HttpContext.Current != null;
            }
            catch
            {
                return false;
            }
        }
    
        private static object GetScope(IContext ctx)
        {
            // note: this is a copy of the private method of Ninject.Web.Common.RequestScopeExtensionMethod#GetScope
            return ctx.Kernel.Components.GetAll<INinjectHttpApplicationPlugin>().Select(c => c.RequestScope).FirstOrDefault(s => s != null);
        }
    
        public static IBindingWhenInNamedWithOrOnSyntax<T> InRequestFallbackScope<T>(this IBindingWhenInNamedWithOrOnSyntax<T> binding)
        {
            Func<IContext, object> fallbackCallback = ctx => IsRequestPresent() ? GetScope(ctx) : StandardScopeCallbacks.Thread(ctx);
            binding.BindingConfiguration.ScopeCallback = fallbackCallback;
            return binding;
        }
    }
    

    如果您处于 Thread 场景中,请确保调用 _kernel.Components.Get&lt;ICache&gt;().Clear(Thread.CurrentThread); 以触发(可能存在)您在此范围 (-> Thread.CurrentThread) 中加载的对象上的 Dispose()。

    【讨论】:

    • 我认为安德斯的第二个答案是等价的,可以处理更多的案例并且代码更少(并且正在使用类似的东西从HttpContext.Current 回退到OperationScope.Current)。我看不到 IsRequestPresent 检查完成了什么 - 请记住 anything can plugin in to the RequestScope stuff。如果一个简单的实现是不可能的,创建一个拉取请求来公开所需的回调,这意味着你不需要跟踪内部实现的变化。
    • 我创建了这个答案,因为 StandardScopeCallbacks.Request 不再存在。老实说,这段代码必须有效,而不是为了美。我知道这不是应该的方式,但对于快速解决方案来说就足够了。我会考虑拉取请求。
    • 为什么没有意义?当一个 webapp 启动并且你尝试获取当前的 httpcontext 时,你会得到一个 juicy 的异常。
    • 为什么?当IsRequestPresent() 返回false 时,GetScope(ctx) 将返回nullFirstOrDefault 不扔?即,我会将 fallbackCallback 的 lambda 替换为 ctx =&gt; GetScope(ctx) ??StandardScopeCallbacks.Thread(ctx); (我认为它会全部崩溃到 return binding.InScope( ctx =&gt; GetScope(ctx) ??StandardScopeCallbacks.Thread(ctx))
    猜你喜欢
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 2011-10-18
    • 2012-08-18
    • 2011-05-20
    • 1970-01-01
    相关资源
    最近更新 更多