February 2016

Volume 31 Number 2

[Data Points]

Refactoring an ASP.NET 5/EF6 Project and Dependency Injection

By Julie Lerman

Just prior to press time, Microsoft announced name changes to ASP.NET 5 and related stacks. ASP.NET 5 is now ASP.NET Core 1.0. Entity Framework (EF) 7 is now Entity Framework (EF) Core 1.0. The ASP.NET 5 and EF7 packages and namespaces will change, but otherwise the new nomenclature has no impact on the lessons of this article.

Julie LermanDependency injection (DI) is all about loose coupling (bit.ly/1TZWVtW). Rather than hardcoding classes you depend on into other classes, you request them from somewhere else, ideally your class’s constructor. This follows the Explicit Dependencies Principle, more clearly informing users of your class about the collaborators it requires. It also allows you to build more flexibility into your software for scenarios such as alternate configurations of a class’s object instance, and it’s really beneficial for writing automated tests for such classes. In my world, which is fraught with Entity Framework code, a typical example of coding without loose coupling is creating a repository or controller that instantiates a DbContext directly. I’ve done this thousands of times. In fact, my goal with this article is to apply what I’ve learned about DI to the code I wrote in my column, “The EF6, EF7 and ASP.NET 5 Soup” (msdn.com/magazine/dn973011). For example, here’s a method where I instantiated a DbContext directly:

public List<Ninja> GetAllNinjas() {
  using (var context=new NinjaContext())
  {
    return context.Ninjas.ToList();
  }
}

Because I used this within an ASP.NET 5 solution and ASP.NET 5 has so much DI support built in, Rowan Miller from the EF team suggested I could improve the example by taking advantage of that DI support. I had been so focused on other aspects of the problem I hadn’t even considered this. So, I went about refactoring that sample bit by bit, until I got the flow working as prescribed. Miller had actually pointed me toward a nice example written by Paweł Grudzień in his blog post, “Entity Framework 6 with ASP.NET 5” (bit.ly/1k4Tt4Y), but I explicitly chose to avert my eyes and not simply copy and paste from that blog. Instead, I worked the ideas out on my own so I could better comprehend the flow. In the end, I was happy to see that my solution aligned well with the blog post.

Inversion of Control (IoC) and IoC containers are patterns that have always seemed a bit daunting to me. Keep in mind that I’ve been coding for almost 30 years, so I imagine I’m not the only experienced developer who never made the mental transition to this pattern. Martin Fowler, a well-known expert in this field, points out that IoC has several meanings, but the one that aligns with DI (a term he created to clarify this flavor of IoC) is about which piece of your application is in control of creating particular objects. Without IoC, this has always been a challenge.

When co-authoring the Pluralsight course “Domain-Driven Design Fundamentals” (bit.ly/PS-DDD) with Steve Smith (deviq.com), I was finally led to use the StructureMap library, which has become one of the most popular IoC containers among .NET developers since its inception in 2005. The bottom line is that I was a little late to the game. With Smith’s guidance, I was able to understand how it works and its benefits, but I still didn’t feel quite solid with it. So after the hint from Miller, I decided to refactor my earlier sample to leverage a container that makes it easier to inject object instances into logic that needs to use them.

But First, Let’s Get DRY

An initial problem in my class that houses the GetAllNinjas class shown earlier, is that I repeat the using code:

using(var context=new NinjaContext)

in other methods in that class, such as:

public Ninja GetOneNinja(int id) {
  using (var context=new NinjaContext())
  {
    return context.Ninjas.Find(id);
  }
}

The Don’t Repeat Yourself (DRY) principle helps me recognize that potential pitfall. I’ll move the creation of the NinjaContext instance into a constructor and share a variable such as _context with the various methods:

NinjaContext _context;
public NinjaRepository() {
  _context = new NinjaContext();
}

However, this class, which should just focus on retrieving data, is still responsible for determining how and when to create the context. I want to move decisions about how and when to create the context higher up in the stream and just let my repository use the injected context. So I’ll refactor again to pass in a context created elsewhere:

NinjaContext _context;
public NinjaRepository(NinjaContext context) {
  _context = context;
}

Now the repository is on its own. I don’t have to keep mucking with it to create the context. The repository doesn’t care about how the context is configured, when it’s created or when it’s disposed. This also helps the class follow another object-oriented principle, the Single Responsibility Principle, because it’s no longer responsible for managing EF contexts in addition to making database requests. When working in the repository class, I can focus on queries. I can also test it more easily because my tests can drive those decisions and won’t be tripped up by a repository that’s designed to be used in a way that doesn’t align with how I may want to use it in automated tests.

There’s another problem in my original example, which is that I hardcoded the connection string into the DbContext. I justified that at the time because it was “just a demo” and getting the connection string from the executing app (the ASP.NET 5 application) to the EF6 project was complicated and I was focused on other things. However, as I refactor this project, I’ll be able to leverage the IoC to pass in the connection string from the executing application. Watch for this further on in the article.

Let ASP.NET 5 Inject the NinjaContext

But where do I move the NinjaContext creation to? The controller uses the repository. I definitely don’t want to introduce EF into the controller in order to pass it into a new instance of the repository. That would create a mess (something like this):

public class NinjaController : Controller {
  NinjaRepository _repo;
  public NinjaController() {
    var context = new NinjaContext();
    _repo = new NinjaRepository(context);
  }
  public IActionResult Index() {
    return View(_repo.GetAllNinjas());
  }
}

At the same time I’m forcing the controller to be aware of EF, this code ignores the problems of instantiating dependent objects that I just solved in the repository. The controller is directly instantiating the repository class. I just want it to use the repository, not worry about how and when to create it or when to dispose it. Just as I injected the NinjaContext instance into the repository, I want to inject a ready-to-use repository instance into the controller.

A cleaner version of the code inside the controller class looks more like this:

public class NinjaController : Controller {
  NinjaRepository _repo;
  public NinjaController(NinjaRepository repo) {
    _repo = repo;
  }
  public IActionResult Index() {
    return View(_repo.GetAllNinjas());
  }
}

Orchestrating Object Creation with IoC Containers

Because I’m working with ASP.NET 5, rather than pull in StructureMap, I’ll take advantage of the ASP.NET 5 built-in support for DI. Not only are many of the new ASP.NET classes built to accept objects being injected, but ASP.NET 5 has a service infrastructure that can coordinate what objects go where—an IoC container. It also allows you to specify the scope of objects—when they should be created and disposed—that will be created and injected. Working with the built-in support is an easier way to get started.

Before using the ASP.NET 5 DI support to help me inject my NinjaContext and NinjaRepository as needed, let’s see what this looks like injecting EF7 classes, because EF7 has built-in methods to wire it up to the ASP.NET 5 DI support. The startup.cs class that’s part of a standard ASP.NET 5 project has a method called ConfigureServices. This is where you tell your application how you want to wire up the dependencies so it can create and then inject the proper objects into the objects that need them. Here’s that method, with everything eliminated but a configuration for EF7:

public void ConfigureServices(IServiceCollection services)
{
  services.AddEntityFramework()
          .AddSqlServer()
          .AddDbContext<NinjaContext>(options =>
            options.UseSqlServer(
            Configuration["Data:DefaultConnection:ConnectionString"]));
}

Unlike my project, which uses my EF6-based model, the project where this configuration is being executed depends on EF7. These next few paragraphs describe what’s happening in this code.

Because EntityFramework .MicrosoftSqlServer was specified in its project.json file, the project references all of the relevant EF7 assemblies. One of these, the EntityFramework.Core assembly, provides the AddEntityFramework extension method to IServiceCollection, allowing me to add in the Entity Framework service. The EntityFramework .MicrosoftSqlServer dll provides the AddSqlServer extension method that’s appended to AddEntityFramework. This stuffs the SqlServer service into the IoC container so that EF will know to use that when it’s looking for a database provider.

AddDbContext comes from the EF core. This code adds the specified DbContext instance (with the specified options) to the ASP.NET 5 built-in container. Any class that requests a DbContext in its constructor (and that ASP.NET 5 is constructing) will have the configured DbContext provided to it when it’s created. So this code adds the NinjaContext as a known type that the service will instantiate as needed. In addition, the code specifies that when constructing a NinjaContext, it should use the string found in the configuration code (which in this case is coming from an ASP.NET 5 appsettings.json file, created by the project template) as a SqlServer configuration option. Because ConfigureService runs in the startup code, when any code in the application expects a NinjaContext but no specific instance is provided, ASP.NET 5 will instantiate a new NinjaContext object using the specified connection string and pass that in.

So that’s all very nicely built-in with EF7. Unfortunately, none of this exists for EF6. But now that you have an idea how the services work, the pattern for adding the EF6 NinjaContext to the application’s services should make sense.

Adding Services Not Built for ASP.NET 5

In addition to services that are built to work with ASP.NET 5, which have nice extensions like AddEntityFramework and AddMvc, it’s possible to add other dependencies. The IServicesCollection interface provides a plain vanilla Add method, along with a set of methods to specify the lifetime of the service being added: AddScoped, AddSingleton and AddTransient. I’ll focus on AddScoped for my solution because it scopes the lifetime of the requested instance to each HTTP request in the MVC application where I want to use my EF6Model project. The application won’t try to share an instance across requests. This will emulate what I was originally achieving by creating and disposing my NinjaContext within each controller action, because each controller action was responding to a single request.

Remember that I have two classes that need objects injected. The NinjaRepository class needs NinjaContext, and NinjaController needs a NinjaRepository object.

In the startup.cs ConfigureServices method I begin by adding:

services.AddScoped<NinjaRepository>();
services.AddScoped<NinjaContext>();

Now my application is aware of these types and will instantiate them when requested by another type’s constructor.

When the controller constructor is looking for a NinjaRepository to be passed in as a parameter:

public NinjaController(NinjaRepository repo) {
    _repo = repo;
  }

but none has been passed in, the service will create a NinjaRepository on the fly. This is referred to as “constructor injection”. When the NinjaRepository expects a NinjaContext instance and none has been passed in, the service will know to instantiate that, as well.

Remember the connection string hack in my DbContext, which I pointed out earlier? Now I can instruct the AddScoped method that constructs the NinjaContext about the connection string. I’ll put the string in the appsetting.json file again. Here’s the appropriate section of that file:

"Data": {
    "DefaultConnection": {
      "NinjaConnectionString":
      "Server=(localdb)\\mssqllocaldb;Database=NinjaContext;
      Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  }

Note that JSON doesn’t support line wrapping, so the string that begins with Server= can’t be wrapped in your JSON file. It’s wrapped here only for readability.

I’ve modified the NinjaContext constructor to take in a connection string and use it in the DbContext overload, which also takes a connection string:

public NinjaContext(string connectionString):
    base(connectionString) { }

Now I can tell AddScoped that when it sees a NinjaContext, it should construct it using that overload, passing in the Ninja­ConnectionString found in appsettings.json:

services.AddScoped<NinjaContext>
(serviceProvider=>new NinjaContext
  (Configuration["Data:DefaultConnection:NinjaConnectionString"]));

With this last change, the solution that I broke while refactoring now works from end to end. The start-up logic sets up the app for injecting the repository and context. When the app routes to the default controller (which uses the repository that uses the context), the needed objects are created on the fly and the data is retrieved from the database. My ASP.NET 5 application takes advantage of its built-in DI to interact with an older assembly where I used EF6 to build my model.

Interfaces for Flexibility

There is one last possible improvement, which is to take advantage of interfaces. If there’s a possibility that I might want to use a different version of my NinjaRepository or NinjaContext class, I can implement interfaces throughout. I can’t foresee needing to have a variation on NinjaContext, so I’ll only create an interface for the repository class.

As shown in Figure 1, the NinjaRepository now implements an INinjaRepository contract.

Figure 1 NinjaRepository Using an Interface

public interface INinjaRepository
{
  List<Ninja> GetAllNinjas();
}
public class NinjaRepository : INinjaRepository
{
  NinjaContext _context;
  public NinjaRepository(NinjaContext context) {
    _context = context;
  }
  public List<Ninja> GetAllNinjas() {
    return _context.Ninjas.ToList();
  }
}

The controller in the ASP.NET 5 MVC application now uses the INinjaRepository interface instead of the concrete implementation, NinjaRepository:

public class NinjaController : Controller {
  INinjaRepository _repo;
  public NinjaController(INinjaRepository repo) {
    _repo = repo;
  }
  public IActionResult Index() {
    return View(_repo.GetAllNinjas());
  }
}

I’ve modified the AddScoped method for the NinjaRepository to tell ASP.NET 5 to use the appropriate implementation (currently NinjaRepository) whenever the interface is required:

services.AddScoped<INinjaRepository, NinjaRepository>();

When it’s time for a new version, or if I’m using a different implementation of the interface in a different application, I can modify the AddScoped method to use the correct implementation.

Learn By Doing, Don’t Copy and Paste 

I’m grateful that Miller gently challenged me to refactor my solution. Naturally, my refactoring didn’t go as smoothly as it might appear based on what I’ve written. Because I didn’t just copy from someone else’s solution, I did some things incorrectly at first. Learning what was wrong and figuring out the correct code led me to success and was hugely beneficial to my understanding of DI and IoC. I hope my explanations will give you that benefit without your having to bump your head as much as I did.


Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other .NET topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of “Programming Entity Framework,” as well as a Code First and a DbContext edition, all from O’Reilly Media. Follow her on Twitter: @julielerman and see her Pluralsight courses at juliel.me/PS-Videos.

Thanks to the following technical expert for reviewing this article: Steve Smith
Steve Smith (@ardalis) is an entrepreneur and software developer with a passion for building quality software. Steve has published several courses on Pluralsight, covering DDD, SOLID, design patterns, and software architecture. He's a Microsoft MVP, a frequent speaker at developer conferences, an author, mentor, and trainer. Find out how Steve can help with your team or project at ardalis.com.