Отклонить отступ InRequestScope для InThreadScope - PullRequest
11 голосов
/ 31 октября 2011

В моем проекте MVC3 я настроил свое ядро ​​для Ninject контекста Entityframework на основе InRequestScope, это прекрасно работает, но у меня есть фоновый бегун, который выполняет некоторое управление рабочим процессом.

Он запускает новыйпоток каждые 5 минут, и я Ninject свои зависимости в этот поток, если я изменяю область видимости на InThreadScipe, метод Dispose срабатывает, но если я изменяю его обратно на InRequestScope, метод Dispose не будет срабатывать.

Есть ли способоткат к InThreadScope, если InRequestScope недоступен?

Обновление: Только что получил ответ на этот вопрос, и почему бы не обновить его дополнительной информацией.Я думаю, что Ninjects немного устарел.У других IoC есть дочерние контейнеры, в которых зарегистрированные временные объекты Transient живут в течение всего дочернего контейнера и удаляются, когда есть дочерние контейнеры.Это гораздо более простой способ объединения, например, веб-API с настраиваемым рабочим, как в приведенном выше сценарии.

Ответы [ 3 ]

14 голосов
/ 31 октября 2011

Существует метод InScope, с помощью которого вы можете указать пользовательское правило области видимости.

Реализация InRequestScope в настоящее время претерпевает изменения с 2.2-2.4.

Итак, перейдите к исходному тексту вашей версии, посмотрите на значения InRequestScope и InThreadScope и создайте амальгаму (которую затем можно использовать как метод расширения наряду с другими InXXXScope методами.

Это будет выглядеть (до того, как вы извлечете его в метод расширения) примерно так:

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

Другой способ - создать два Bind с соответствующими ограничениями, такими как WhenInjectedInto<T>, для настройки области видимости на основе контекстной привязки .

6 голосов
/ 31 октября 2011

Благодаря Рубену я нашел решение, однако в его псевдокоде пробралась небольшая ошибка, и, поскольку сегодня понедельник, и я устал, я не сразу его увидел: D

StandardScopeCallbacks.Request

делегат и

StandardScopeCallbacks.Request ?? StandardScopeCallbacks.Thread 

всегда будут возвращать левую сторону, поскольку делегат никогда не будет нулевым.

Есть два способа сделать это правильно,

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 Использование метода InScope

.InScope(ctx => StandardScopeCallbacks.Request(ctx) ?? StandardScopeCallbacks.Thread(ctx))
2 голосов
/ 29 мая 2013

Это то, что я написал, чтобы область запроса была в первую очередь, а поток - резервным.

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

Если вы находитесь в сценарии потока, убедитесь, что вы вызываете _kernel.Components.Get<ICache>().Clear(Thread.CurrentThread);, чтобы вызвать (возможно, существующий) Dispose () для объектов, которые вы загрузили в этой области (-> Thread.CurrentThread).

...