我使用的是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;?我应该知道有负面影响吗?
答案 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<>
。
我不明白为什么,而且看起来反直觉,但这就是它的工作原理。