An Introduction to Dependency Injection in .NET MVC

An Introduction to Dependency Injection in .NET MVC

Written by Unknown on Oct 02, 2014

A requirement to writing clean, maintainable code that your software and anyone maintaining it deserves

    This article will give a brief introduction to the concept of Dependency Injection, specifically using .NET MVC in C#. By covering the basics and fundamental concepts required to utilize this technology, we ensure proper implementation. The popular Dependency Injection library SimpleInjector will be used, leaving us with a clean, maintainable web project.

As a software developer, we face many challenges outside of the context of client appeasement. Providing the client with the software they deserve and expect is of course priority number one. However, internally, we have our own goals. Most of these goals center on striving to improve ourselves as developers. Learning new technologies, design patterns and methods are some of the many ways we do this. And ultimately, we want maintainable code.

Writing clean, maintainable code is important for many reasons. First, it is easier for a new developer to pick up and understand what’s going on (or even yourself, revisiting a project many months or years later). Second, it is easier to implement new features, and third, it is easier to find and debug issues your QA department finds. Laying the groundwork might be a bit of extra work in the beginning, but the payoff is invaluable to both you and the client. Unmaintainable code is a headache for everyone. You have to work harder and longer, and the client sees (sometimes unreasonably) bigger bills. And, depending on how big that bill is, you or the company you work for might end up having to eat some of the cost.

Apart from business sensibility, there’s also a little bit of a selfish side of things. Writing clean code is fun. For me, looking at freshly written code that broke down a complex task into clean, reusable code is immensely satisfying. It’s almost like art. It takes a certain level of understanding and expertise to look at something and truly appreciate the work that went into it. This is true of everything in life, including software.

While this article is not explicitly centered on the “art” of programming, I will discuss a technique crucial to writing clean, maintainable code. The rest of this article will be a bit techier, but at a higher level. We’re not getting into the nitty-gritty, but rather exposing you to a new way of doing things.

Enter Dependency Injection

    Dependency Injection (hereby referred to as DI) can be summarized with one idea: Classes should rely on the application architecture to provide its dependent services. It sounds quite simple, and at its core, it is. But, there’s a lot that must be in place for DI to be implemented properly. DI relies on a set of software design principles and patterns called SOLID. As a developer, you should be extremely familiar with these concepts. If you’re not, stop reading this article and read this series of articles instead. It is important to understand that DI is a universal programming concept. It applies regardless of language or framework. However, for this article, I am going to show an example implementation in a .NET MVC project using C#.

An Example Scenario

    Let’s start off with a very simple scenario:  Assume a client has tasked you with creating a website for their jewelry store. The first feature you decide to tackle is a basic product (and price) listing. To make things more interesting, some items only appear to subscribed members. That is, members that have registered accounts and who have logged in successfully to the store.

So right now, our product controller looks like this:

    public class ProductController : Controller
    {
        private readonly ProductService productService;
        public ProductController()
        {
            productService = new ProductService();
        }
 
        public ActionResult Index()
        {
            var products = productService.GetProducts(User);
            return View(products);
        }
    }

And our product service looks like this: 

    public class ProductService
    {
        private readonly DbSet<Product> products;
        public ProductService()
        {
            products = new DataContext().Set<Product>();
        }
 
        public IEnumerable<Product> GetProducts(IPrincipal user)
        {
            var isMember = user.Identity.Name.Equals("specialmember@email.com");
 
            IQueryable<Product> results;
 
            if (isMember)
            {
                results = products;
            }
            else
            {
                results = products.Where(x => !x.IsPremium);
            }
 
            return results;
        }
    }

When we are visiting the site anonymously, we see: 

dependency injection example 1

When we are visiting the site whilst logged in as a paying member, we see: 

dependency injection example 2

And so the requested feature is now complete, and we can move on to the next. But, what if we want to check if the current user is a paying member elsewhere on the site? Or what if we moved away from MVC and to another web framework? From Entity Framework for MSSQL to Azure? Our code would pretty much have to be written completely from scratch if any of these changes were to come down the pipe. Our code is not reusable and does not account for the future.

An Example Scenario: Refactored

    With a little refactoring, following the SOLID principles, and implementing DI, we can drastically clean up our code and arrive at something much more maintainable.

Our product controller now looks like this:

    public class ProductController : Controller
    {
        private readonly IProductService productService;
        public ProductController(IProductService productService)
        {
            this.productService = productService;
        }
 
        public ActionResult Index()
        {
            var products = productService.GetProducts();
            return View(products);
        }
    }

You’ll notice that we are no longer manually instantiating our Productservice. Instead, we take it in as a parameter to our constructor. We also are no longer dependent on a concrete class, but rather an interface. If you’re familiar with MVC, then you know that our controller instances are created for us by the framework when needed. So you might be asking yourself how the framework is going to know how to provide us with an IProductService. We’ll get to that in a minute, but it’s good to keep this in mind. Also, note that this is what we spoke about earlier. “DI can be summarized with one idea: Classes should rely on the application architecture to provide its dependent services.”

This is what our product service looks like:

    public class AuthorizedProductService : IProductService
    {
        private readonly IProductRepository productRepository;
        private readonly IPermissionsManager permissionsManager;
 
        public AuthorizedProductService(IProductRepository productRepository, IPermissionsManager permissionsManager)
        {
            this.productRepository = productRepository;
            this.permissionsManager = permissionsManager;
        }
 
        public IEnumerable<Product> GetProducts()
        {
            var userIsMember = permissionsManager.IsPayingMember();
            return userIsMember ? productRepository.GetAllProducts() : productRepository.GetNonPremiumProducts();
        }
    }

You’ll notice here that we are now dependent on the IProductRepository and IPermissionsManager interfaces instead of directly creating an EF DataContext. Our logic for determining if a user is a paying member is also abstracted out, which is good. Remember Single Responsibility?

Let's take a look at our new Product repository: 

    public class ProductRepository : IProductRepository
    {
        private readonly IDbSet<Product> products;
 
        public ProductRepository(DbContext context)
        {
            products = context.Set<Product>();
        }
 
        public IQueryable<Product> GetAllProducts()
        {
            return products;
        }
 
        public IQueryable<Product> GetNonPremiumProducts()
        {
            return products.Where(x => !x.IsPremium);
        }
    }

This class is now re-usable. We can query for our products in any part of the application, and the logic remains consistent. In our constructor, we are injecting our EF DbContext and using it to perform our database interaction. If we were to switch to a different ORM or database engine, this would be the only class we’d have to modify. Everything else would just work.

Let’s also take a look at our new Permissions manager:

    public class PermissionsManager : IPermissionsManager
    {
        private readonly IPrincipal user;
 
        public PermissionsManager(IPrincipal user)
        {
            this.user = user;
        }
 
        public bool IsPayingMember()
        {
            return user.Identity.Name.Equals("specialmember@email.com");
        }
    }

Our logic for determining if the current user is a paying member is all contained here. Our product service is no longer responsible for multiple things, and we can use this class anywhere. Also, we no longer have to pass around our MVC User from the controller all the way down where it’s needed. We’re injecting here, directly into the class that depends on it.

Our project should now have all the pieces it needs to perform its duties again. However, we are missing one crucial piece. How will MVC know how to provide our product controller with an IProductService. And how will it know how to provide our product service with an IProductRepository? Or an IPermissionsManager?

The answer is to utilize a tool called a Container. Please note that DI does not require the use of a container, and can be implemented without one (look up “poor man’s DI”). It is only a tool to aid in the process.

For this example, I will be using a popular .NET DI Container called SimpleInjector. There are many DI containers out there, but we’ve found SimpleInjector to be our favorite. Play around with the popular ones and see which one you like. They’re all worthy of your time.

To hook up our DI container, we must tell it how to “resolve” our dependencies. This is called commonly referred to as your dependency registrations.

    public class SimpleInjectorConfiguration
    {
        public static void Configure()
        {
            var container = new Container();
 
            container.Register<IPermissionsManager, PermissionsManager>();
            container.Register<IProductRepository, ProductRepository>();
            container.Register<IProductService, AuthorizedProductService>();
 
            container.RegisterPerWebRequest<DbContext>(() => new DataContext());
            container.RegisterPerWebRequest<IPrincipal>(() =>
            {
                var currentUser = HttpContext.Current.User;
                if (currentUser == null && container.IsVerifying()) return new VerifyingUser();
                return currentUser;
            });
 
            container.Register<IUserStore<ApplicationUser>>(() =>
                new UserStore<ApplicationUser>(new ApplicationDbContext()));
 
            container.Verify();
            DependencyResolver.SetResolver(new SimpleResolver(container));
        }
    }

In this configuration class, we simply tell our container how to resolve each dependency. “When I ask for an IPermissionsManager, give me a PermissionsManager… When I ask for an IProductService, give me an AuthorizedProductService.” In this simple example, it’s quite easy to discern what’s going on here.  At the end, we register the built in MVC membership provider and verify that we have registered everything correctly. Lastly, we tell MVC to use the container we’ve just created as our Dependency Resolver.

Launching the site and hitting our products page returns us with the same results as before.

Anonymous:

dependency injection example 3

Logged in as a paying member: 

dependency injection example 4

Conclusion

DI is extremely useful. It takes a little bit of extra work and maybe a little “boilerplate” code to set up in the beginning, but is worth it 10-fold in the long run. We can easily swap out any of our dependencies for any other concrete implementation of our interfaces. We’d create a new class, change one single line of code in our SimpleInjectorConfiguration, and everything would just work. The concept of Dependency Injection is essential to any good software developer who wants to write clean, maintainable code.

Comments

comments powered by Disqus