Using Entity Framework DbContext with Dependency Injection

Sponsored by #native_company#
#native_desc# #native_cta#

I'm a huge fan of Dependency Injection (DI). It's gotten to the point where it's almost in my blood (pun intended). DI is standard issue on all my team's projects, and I fail any code reviews that don't include it unless there's a really solid reason why it doesn't work for that particular scenario.

For quite a long time, I didn't include Entity Framework (EF) DbContext items in this mental pool of "things that should be injected". This is mostly because there was a very simple way of creating and disposing a DbContext and I was perfectly satisfied with using it. Until I wasn't. And because of that dissatisfaction, combined with the advent of my team using Dependency Injection, I went looking for way to make EF and DI play nicely together, to make injecting a DbContext nice and easy. Turns out I didn't have to look too much. This post details what I found, and shows injection might be easier than you think it is.

A disposable syringe, with a green liquid inside it

Even better: no syringes needed!

The Old Way

The idea that took a while to take hold in my mind was this: a DbContext is just another dependency, exactly like all those Repository classes we programmers tend to build. The issue, at least for me, was that I did not think of it that way. See, I used to use DbContext like this:

public void SaveItem(Item item)
{
    using(MyContext entities = new MyContext())
    {
        entities.Items.Add(item);
        entities.SaveChanges();
    }
}

This structure is very nice and simple, because we a) can use it anywhere and b) the using() clause guarantees that we won't have a bunch of open DbContext items everywhere, since the context gets disposed at the end of the clause. Most importantly, it works, and works well.

But since I'm always trying to stave off my inevitable obsolescence, I became unsatisfied with this, partly because it was a lot of extra curly braces and partly because I was starting to truly enjoy using dependency injection. And so I began searching for a way to include our DbContext as items that can be injected.

The New Way

I'll skip right to the solution. We use StructureMap primarily, and so below is some setup code and a sample controller showing how we include our DbContext in our container and subsequently inject it into our controllers (this will look different but behave mostly the same way in other DI containers, like Unity, Castle Windsor, or SimpleInjector).

public DefaultRegistry() {
    Scan(
        scan => {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
			scan.With(new ControllerConvention());
        });
    
    //Entity Framework Context
    var myContext = new EntityFrameworkContext();
    myContext.Configuration.ProxyCreationEnabled = false;
    For<EntityFrameworkContext>().Use(myContext);
}

public class MyController : ApiController
{
    private EntityFrameworkContext _myContext;

    public MyController(EntityFrameworkContext myContext)
    {
        _myContext = myContext;
    }
}

Let me explain some of what is happening in these code snippets.

First off, when we add our Entity Framework context to StructureMap's container, we disable a property called ProxyCreationEnabled. In effect, this means that Entity Framework will not load related entities unless explicitly told to do so via the Include() method. We do this so that we don't load more data than necessary, and because our Entity Framework items will almost immediately get transferred into data transfer objects and then serialized into JSON, and we don't want any serialization problems.

Secondly, I want to point out that we are injecting the concrete class, not an interface as you would do with many other injectable objects. This is intentional, mostly because an appropriate interface doesn't exist by default. But also, this is because DbContext instances are very lightweight, and don't need a lot of extra cruft that many other dependencies do when being injected.

Thirdly, I want to point out that in StructureMap, the default lifetime of an object is called Transient, which means the object only exists for the life of the web request. This works out perfectly for DbContext; since it is lightweight it can be created easily on every request made to our application.

UPDATE Nope, that paragraph is wrong. The default lifetime IS transient, but that's not what is happening here. In this case, we are creating a single instance of our DbContext and using that single instance every time a request is created. This is probably fine for many implementations, but for completeness's sake here's what it SHOULD be for a transient DbContext:

public DefaultRegistry() {
    Scan(
        scan => {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
			scan.With(new ControllerConvention());
        });
    
    //Entity Framework Context
    For<EntityFrameworkContext>().Use(context => CreateNewContext(context));
}

public EntityFrameworkContext CreateNewContext(IContext context)
{
    var myContext = new EntityFrameworkContext();
    myContext.Configuration.ProxyCreationEnabled = false;
    return myContext;
}

Special thanks to commenters Michael Whelan, Phil Bolduc, and Steve Glendinning (among others) who pointed out this mistake. Thanks guys!

Turns out injecting an Entity Framework DbContext into our controller was much simpler than I originally thought. I dunno why I didn't do this sooner...

Summary

Injecting an Entity Framework DbContext into classes which need it is almost as simple as any other class, just with a few caveats. If you just keep those caveats in mind, you'll have no trouble using Entity Framework with Dependency Injection.

Did I miss something here? Want to share how your team started using Entity Framework in Dependency Injection scenarios? Share in the comments!

Happy Coding!

Matthew Jones

Matthew Jones

I'm a parent, a husband, a geek, a web developer, and a speaker, in roughly that order.

Read More
Using Entity Framework DbContext with Dependency Injection
Share this