Dependency Injection in ASP.NET Core
In a recent Community Standup, one of the questions that was asked of the team was: “How do I get started with Dependency Injection in ASP.NET Core?” This is where we’re going to answer your question, because in this post we’re going to share how dependency injection is used in ASP.NET Core and how you can configure it to meet your needs.
Dependency Injection is an application design that enables class dependencies to be automatically added to an instantiated object. The net effect is a loose coupling between classes, with dependencies provided to a class as constructor parameters or properties. These parameters or properties typically reference an interface so that a concrete object that implements that interface can be passed in. Consider the following class design:
This overly simple tax calculator class requires an ITaxingAuthorityRules object to be passed in to it in order to be created. This interface implements a method called “CalculateTax” and returns a decimal. In the use of this tax calculator class, I could pass in different implementations of the ITaxingAuthorityRules for different countries or for a personal tax versus a corporate tax or even pass in a fake object for the purposes of testing the CalculateTaxesDue method. The promise of this approach is this decoupling of resources that no longer need to know how they are being used, but can be focused on doing one thing and doing it well. We continue to use our TaxCalculator into the future with new taxing rules. In using the Dependency Injection design, its a common practice to use a container object that is used to construct all of the objects that will be used in the application. This container is configured with knowledge of many of the default interface to concrete class mappings so that as interfaces are requested by new classes an appropriate class can be created and injected into the new class.
Dependency Injection in ASP.NET Core
With ASP.NET Core, dependency injection is a fundamental tenet of the framework. All classes instantiated by the framework are done so through the container service that is maintained by the framework in a container and configured by default in the Startup/ConfigureServices method. This method looks like the following in an RC1 default template:
In this code, an EntityFramework context, the identity configuration, the MVC framework, and mappings for an IEmailSender and ISmsSender are configured for the dependency injection container to be able to inject into other classes that it creates. The IServiceCollection object passed into this method has a number of methods and extension methods connected to it that enable this simple mapping and registration of services. Typically when you want to register your own mappings with the container, you will use either the AddTransient or AddSingleton methods register your mappings. The AddTransient method instructs the container to create a new instance of the designated class for each instance of each created class that requires it. AddSingleton creates one instance and passes that instance into each created class that requires it. More details about configuring the container are available in the ASP.NET Core docs.
I like to add the Configuration that was built in the constructor of the Startup class to the container with a statement in the ConfigureServices methods to reads like the following:
services.AddSingleton<IConfiguration>(_ => Configuration);
This will stash the current value of the Configuration property in the container and make the configuration accessible to my entire project when I need it.
Controllers are very easy to inject dependencies into, and a great example is the constructor for the default AccountController:
This constructor accepts five input parameters and places their values into private readonly fields. These parameters were all configured by the ConfigureServices methods, except for the ILoggerFactory. This interface, along with the IApplicationBuilder and IHostingEnvironment are added to the container by the ASP.NET framework. Without having to write methods to configure and load each of these dependencies, our AccountController class can start working with them.
The Views in our project can have objects injected into them by the container by using the new @inject directive:
The syntax indicates that the first argument is the type to require and the second argument is the variable name that will be exposed to the rest of the razor page.
The default ASP.NET container is simple and does not offer the robust configuration and performance options that are available with other containers. Fortunately, you can swap out the default container with one of the community-created full featured ones that is already available as a NuGet package. Autofac is one that is already available for ASP.NET Core, and you can add it to your project by referencing both the Autofac and Autofac.Extensions.DependencyInjection packages. Next, change the signature of the ConfigureServices method to return an IServiceProvider. Finally, add some configuration code at the end of the method to copy the registered services over to Autofac and register it as the new service provider:
Very cool… now my web application is using Autofac to resolve dependencies.
Dependency Injection is a design pattern for your classes. ASP.NET Core makes it easy to get started with this design pattern by shipping a container that you can use with your application. Configure your application’s controllers, views, and other classes that are instantiated by the framework with parameters on the constructor method to have those types automatically created and passed in to your class. You can learn more about ASP.NET Dependency Injection from our documentation.