Ninject InRequestScope возвращается к InThreadScope
В моем проекте MVC3 я настроил свое ядро на Ninject контекст Entityframework на основе InRequestScope, это работает отлично, но у меня есть фоновый бегун, который выполняет некоторые управления рабочим процессом.
Он запускает новый поток каждые 5 минут, а я Ninject меняет зависимости в этом потоке. Если я изменю область действия на InThreadScipe, то будет запущен метод Dispose, но если я верну его обратно в InRequestScope, метод Dispose не будет запущен.
Есть ли способ отступить к InThreadScope, если InRequestScope недоступен?
Обновление: Только что получил ответ на этот вопрос и почему бы не обновить его дополнительной информацией. Я думаю, что Ninjects способ обработки жизненного времени немного устарел. Другие IoC имеют дочерние контейнеры. Транзитные зарегистрированные объекты живут в течение всего дочернего контейнера и размещаются, когда находятся дочерние контейнеры. Это гораздо более простой способ объединения, например, Web API с пользовательским рабочим, как описано выше.
Ответы
Ответ 1
Существует метод InScope
, с помощью которого вы можете указать настраиваемое правило видимости.
Реализация InRequestScope в настоящее время претерпевает изменения с 2.2-2.4.
Итак, перейдите к исходной версии вашей версии, посмотрите на тег InRequestScope
и InThreadScope
и создайте амальгаму (которую вы затем можете вставить как метод расширения вместе с другими методами InXXXScope
.
Он будет выглядеть (прежде чем вы извлечете его в метод расширения), например:
Bind<X>.To<T>().InScope( ctx => ScopeContext.Request(ctx) ?? ScopeContext.Thread(ctx))
Другим способом является создание двух Bind
ings с соответствующим ограничением, например WhenInjectedInto<T>
, чтобы настроить область охвата на основе контекстной привязки.
Ответ 2
Благодаря Рубену я нашел решение, однако там прокрался небольшой клочок там в его псевдокоде и с тех пор, как в понедельник и я устал, я не видел его сразу: 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))
Ответ 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<ICache>().Clear(Thread.CurrentThread);
для запуска (возможно, существующего) Dispose() для объектов, загруженных в эту область (- > Thread.CurrentThread).