注入Ninject范围对象以进行确定性处置

时间:2017-07-31 12:41:01

标签: c# entity-framework inversion-of-control ninject

我想在我的应用程序中使用Ninject自定义作用域,以便将DbContext的单个激活范围包含到我的核心域处理程序中。我遇到了麻烦,因为CommandScope对象实现了INotifyWhenDisposed接口,这是Ninject的一部分,我不想在我的域中依赖Ninject。

我已经尝试了许多其他方法来获取代码中的依赖项,但没有成功,包括使用Ninject Factories来公开IScopeFactory和Func依赖项。在后一种情况下,问题是(我认为)Ninject没有连接INotifyWhenDisposed.Dispose事件,因为绑定目标是Func而不是IDisposable本身。

无论如何,这是我想要实现的代码。

的IoC

 Kernel
     .Bind<MyDbContext>()
     .ToSelf()
     .InScope(x => CommandScope.Current)
     .OnDeactivation(x => x.SaveChanges());

CommandScope

public class CommandScope : INotifyWhenDisposed
{
    public event Dispose;

    public bool IsDisposed { get; private set; }

    public static CommandScope Current { get; private set; }

    public static CommandScope Create()
    {
        CommandScope result = new CommandScope();
        Current = result;
        return result;
    }

    public void Dispose()
    {
        IsDisposed = true;
        Current = null;
        Dispose?.Invoke(this, EventArgs.Empty);
    }
}

在我的域内...

public class Pipeline<TRequest, TResponse>
{
    readonly IRequestHandler<TRequest, TResponse> innerHandler;

    public Pipeline(IRequestHandler<TRequest, TResponse> handler)
    {
        innerHandler = handler;
    }

    public TResponse Handle(TRequest request)
    {
         using(CommandScope.Create())
         {
             handler.Handle(request);
         }
    }
}

2 个答案:

答案 0 :(得分:1)

你可以使用装饰器模式(需要一个接口)并且只让装饰器实现INotifyWhenDisposed接口 - 然后将装饰器放在组合根中 - 无论如何你需要一个ninject参考。

Alternatevily,你可以使用一个Func Factory,创建一个IDisposable来实现INotifyWhenDisposed(消费库不需要知道这个)。在组合根中访问实例时,您仍然可以将其强制转换为INotifyWhenDisposed(实际上可能没有必要)。例如:

.InScope(x => (INotifyWhenDisposed)CommandScope.Current)

对设计的评论:我想高调建议将CommandScope分成两类:工厂和实际范围。 此外,从长远来看,您可以通过确保新范围(由Create创建)不会替换尚未处置的旧范围来节省大量头痛。否则你很可能会错过你介绍的漏洞。

答案 1 :(得分:0)

从Ninject的ICache清除范围对象将迫使Ninject关闭并处置由范围控制的所有实例:

var activationCache = Kernel.Get<Ninject.Activation.Caching.ICache>();
activationCache.Clear(CommandScope.Current);

你也可以认为NamedScope extension有更好的替代单身模式CommandScope。