Ninject InRequestScope fallback to InThreadScope

后端 未结 3 1640
抹茶落季
抹茶落季 2021-01-11 14:28

In my MVC3 project I\'ve setup my kernel to Ninject the Entityframework context on a InRequestScope basis, this works perfect. But I have a ba

相关标签:
3条回答
  • 2021-01-11 15:08

    Thanks to Ruben I found a solution, however there sneaked in a little bug there in his pseudo code and since its a monday and Im tired I didnt see it right away :D

    StandardScopeCallbacks.Request
    

    Is a delegate and

    StandardScopeCallbacks.Request ?? StandardScopeCallbacks.Thread 
    

    will always return the left side since the delegate will never be null.

    There are two ways of doing this correctly,

    1 ExtensionMethod

    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 Using the InScope method

    .InScope(ctx => StandardScopeCallbacks.Request(ctx) ?? StandardScopeCallbacks.Thread(ctx))
    
    0 讨论(0)
  • 2021-01-11 15:10

    There's an InScope method, with which you can specify a custom scoping rule.

    The implementation of InRequestScope is currently undergoing change from 2.2-2.4.

    So go to the source of your version, look at the impl of InRequestScope and InThreadScope and create an amalgam (which you can then slot in as an extension method alongside the other InXXXScope methods.

    It'll look (before you extract it into an extension method) something like:

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

    The other way is to create two Bindings, with an appropriate constraint such as WhenInjectedInto<T> to customize the scoping based on the contextual binding.

    0 讨论(0)
  • 2021-01-11 15:24

    This is what I composed to have the request scope in the first place and the thread as a fallback.

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

    If you are in the Thread scenario make sure you call _kernel.Components.Get<ICache>().Clear(Thread.CurrentThread); to trigger the (maybe existing) Dispose() on the objects you loaded in this scope (-> Thread.CurrentThread).

    0 讨论(0)
提交回复
热议问题