0

I face an issue where I want to inject Entity Frameworks DbContext into a service class, in a WPF application. The problem is that the service classes are instantiated and contained by the view models. That could mean a rather long life time for DbContext, if injected directly into the service.

The solution I have come up with, is to inject a DbContextFactory instead. It is described by a very simple interface:

public interface IContextFactory<out T> where T : DbContext
{
    T Create();
}

When created a service, any class that implements IContextFactory can then be injected, like this:

private readonly IContextFactory<MyCustomContext> _factory;

public MyService(IContextFactory<MyCustomContext> factory)
{
    _factory = factory;
}

Which makes it really easy to get and use an instance of the context, in a disposable manner:

public async Task AddEntity(MyEntity entity)
{
    // Some validations first

    using (var db = _factory.Create())
    {
        db.Add(entity);
        await db.SaveChangesAsync();
    }
}

Is this a good way to do things? And are there any ways I could improve upon my concept?

1
  • 2
    looks perfectly reasonable to me. – JonasH Mar 4 '20 at 13:57
1

Is this a good way to do things?

Perfectly reasonable approach, and very valid use case. I've spent literal weeks fixing bugs cause by a library originally being used in a web context (= short lifespans) but later being used in a Windows service (= indefinite lifespan), and had to implement the same solution as you're trying to now.

And are there any ways I could improve upon my concept?

In the interest of not reinventing the wheel, I ended up solving this issue in the past using NInject.Extensions.Factory since the codebase in question was already using NInject.1

The nice thing about this extension is that it automatically instantiates any Func<T> constructor parameter type as a () => new T(); method, but with full implicit DI support for T itself. You only have to register your T itself in the DI framework, as would already be the case anyway.

That DI support, in my opinion, is what should steer you away from a factory and instead push you towards a more "DI-factory" approach. With regular factories, it's hard to account for your product's own dependencies without hardcoding them (which defeats the purpose of DI). You could inject them into the factory itself, but then what happens when one of these dependencies should also come from a factory? The cycle repeats. You'll end up with a lot of factories.

Comparatively, the NInject extension I used only required me to install it, and my job was done. It didn't require any configuration or code, I just started using funcs where I pleased.1

I would assume/hope similar extensions exist for other DI frameworks. If not, I would still advise you to look at involving your DI framework of choice to see if your factories can't be handled by a simple delegate instead, just to cut down on some boilerplate factories.


1 I'm not affiliated with the extension in any way. My lauding over the benefits it provides isn't specific to that extension (others could be providing it too), it's just the only one I personally have worked with or heard about.

1

Just to provide an proper answer. This looks like the correct approach to me, it is easy to read and it is fairly obvious what is going on.

We are using a similar approach, i.e. the Repository/unitOfWork pattern where the dbContext is wrapped in another object. But the dbContext lifetime is managed the same way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.