I'm using ASP.NET Core, and its builtin DI container. I'm using a third-party library (NLog) which I can't change.
My Foo
class has a dependency (by constructor injection).
public class Foo {
private readonly IMyContext _context;
public Foo(IMyContext context) { _context = context; }
// etc.
}
However the library caches the Foo
instance for the duration of the app (that's outside my control). That means it also caches the dependency. And that dependency must not be cached, because it's an EF context which should be scoped.
An alternative is to inject IServiceProvider
, and then to create instances myself.
public class Foo {
private readonly IServiceProvider _sp;
public Foo(IServiceProvider sp) { _sp = sp; }
// etc.
public void bar() {
var context = _sp.GetService<IMyContext>();
// use it
}
}
But as before, that IServiceProvider
instance would be cached for the lifetime of the app.
Is that "safe"? Are there negative repercussions I should know about?
Addendum to @CodeCaster's excellent solution.
It's important to change
Func<Dependency>
toFunc<Owned<Dependency>>
. Otherwise the container won't return new instances each time, even though you're using a delegate factory.Probably has something to do with the fact that a long-lived component (singleton) depends on a short-lived component (per-transaction). The
Func<>
prevents the captive dependency bug, but for the factory to also give you new instances each time, it needs to beOwned<>
.I don't understand why, and it seems counter-intuitive, but that's how it works.
You don't want to inject your IoC container anywhere. That's a bad practice that allows for sloppy coding, and makes unit testing harder, amongst many other reasons.
Instead introduce a factory that can be injected and create a context on demand:
Now if you inject this into your
Foo
:Any decent dependency injection framework can resolve the
Func<TContext>
parameter of theDbContextFactory
, and pass a func there that creates an instance per request.