它是安全的吗?缓存IServiceProvider的应用程序的生命周期?

时间:2017-03-10 10:25:40

标签: .net dependency-injection asp.net-core

我使用的是ASP.NET Core及其内置的DI容器。我使用的第三方库(NLog)无法改变。

我的Foo类具有依赖关系(通过构造函数注入)。

public class Foo {
  private readonly IMyContext _context;
  public Foo(IMyContext context) { _context = context; }
  // etc.
}

但是,库会在应用程序的持续时间内缓存Foo实例(这不在我的控制范围内)。这意味着它还缓存了依赖关系。并且不能缓存该依赖关系,因为它是一个应该限定范围的EF上下文。

另一种方法是注入IServiceProvider,然后自己创建实例。

public class Foo {

  private readonly IServiceProvider _sp;
  public Foo(IServiceProvider sp) { _sp = sp; }

  // etc.

  public void bar() {
    var context = _sp.GetService<IMyContext>();
    // use it
  }

}

但与之前一样,IServiceProvider实例将在应用的生命周期内进行缓存。

这是&#34;安全&#34;?我应该知道有负面影响吗?

2 个答案:

答案 0 :(得分:4)

您不希望将IoC容器注入任何地方。这是一种糟糕的做法,允许进行草率编码,并使单元测试更加困难,还有许多其他原因。

而是引入一个可以注入并按需创建上下文的工厂:

public interface IDbContextFactory<TContext>
{
    TContext Create();
}

public class DbContextFactory<TContext> : IDbContextFactory<TContext>
    where TContext : DbContext
{
    private readonly Func<TContext> _contextCreator;

    public DbContextFactory(Func<TContext> contextCreator)
    {
        _contextCreator = contextCreator;
    }

    public TContext Create()
    {
        return _contextCreator();
    }
}

现在,如果您将此注入Foo

public class Foo 
{
    private readonly IDbContextFactory<MyContext> _contextFactory;
    public Foo(IDbContextFactory<MyContext> contextFactory)
    { 
        _contextFactory = contextFactory;
    }

    public void bar() {
    {
        using (var context = _contextFactory.Create())
        {
            // use your freshly instantiated context
        }
    }
}

任何合适的依赖注入框架都可以解析Func<TContext>的{​​{1}}参数,并在那里传递一个func,为每个请求创建一个实例。

答案 1 :(得分:0)

@ CodeCaster优秀解决方案的附录。

Func<Dependency>更改为Func<Owned<Dependency>>非常重要。否则,即使您正在使用委托工厂,容器也不会每次都返回新实例。

可能与长寿命组件(单例)依赖于短期组件(每个事务)这一事实有关。 Func<>可以防止强制性依赖性错误,但是工厂每次都会为您提供新实例,它必须是Owned<>

我不明白为什么,而且看起来反直觉,但这就是它的工作原理。