Leveraging Dependency Injection in ASP.NET Core

Millions of software has been built in last couple of decades which helped in coming up a set of patterns for resolving different problems and we have a ready reference as GoF design patterns from quite long now. In last decade, Inversion of Control and one of its implementation Dependency Injection (DI) became one of most used pattern across platforms for building great soft wares. Agile methodology for building software which focuses on small releases and more adaptive to the changes, made it very important tool. In this post, we will discuss Dependency Injection and different.

What is Dependency Injection?

Dependency Injection is a design pattern which is an implementation of Inversion of Control (IoC) that provides us a way to resolve dependencies. Objects works in collaboration model and the whole communication becomes pretty complex as system grows.  Inversion of Control says that the objects should not itself create the object/component on which they are dependent to their work, instead these are passed from external sources.

ASP.NET Core and DI

Due to DI’s long list of advantages it has become the norm in software development. But implementation in earlier versions of ASP.NET was not straight forward. Although there are different extensions and libraries made our life easy but ASP.Net as a framework was not open for the same. Due to these kind of new challenges, Microsoft has overhauled the complete framework and made the changes from ground up. The new framework is modularized and using the DI at its core. ASP.Net Core itself provides basic IoC container that we will discuss and later we will how we can use other.

Default container in ASP.NET Core

As mentioned earlier that ASP.NET Core uses DI for instantiating all its components and services. This container is configured in startup.cs class which is the entry point to an ASP.NET Core application. In Startup.cs we have method ConfigureServices which is where we configure all the services that can be later used in the entire application’s life cycle. Let’s see what all are the options provided by ASP.NET core.

aspnetdicore

ASP.NET Core provides above three options to register the services. Let’s discuss each.

AddTransient

Services registered using this method get instantiated each time it is accessed. If we have a service which is used multiple places in same request, a new instance would be created each time.

This method should be used for lightweight, stateless and rarely used services. Let see an example.

Here I have created a service named as TestService which has a method named as GetUniqueId. In this method, I am returning the hash code of the for the instance to check the uniqueness of the instance as

    public class TestService : ITestService
    {
        public int GetUniqueId()
        {
            return this.GetHashCode();
        }    
    }

This service is injected at two places in the sample MVC application

  1. In my home controller as
        public class HomeController : Controller
        {
            private ITestService testService;
    
            public HomeController(ITestService _testService)
            {
                this.testService = _testService;
            }
            public IActionResult Index()
            {
                ViewBag.ServiceInstanceId = testService.GetUniqueId();
                return View();
            }
        }
    
  2. And in my view (Yes we can inject services in the View as well) as
    cshtmlinject

Here service is injected in it at line 1 and called the GetUniqueId method at line 6. While at Line 4, unique Id for the instance is displayed that got injected in home controller. Now it’s time to test the application and register the service as

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddTransient<ITestService, TestService>();
        }

When we run the application
addtransient
Here we can see that in the same request we are getting two instances as expected.

AddScoped

In case of AddScoped, only one instance is created for each request, regardless the number of times it is used in the request. So if you have a service which maintains some state in each request or used frequently then it could be a better choice.

In the same example, we will change the registration of service as

services.AddScoped<ITestService, TestService>();

And run the application
addscoped1
Here we see that only one instance created for the same request. Let’s see multiple requests
addscoped2
As expected here, two different instances gets created for different request while it is unique per request.

AddSingleton

As the name suggests, it created only once instance which get created in the first request itself. In every subsequent request, same instance is used. So, if there is requirement of a singleton behavior, maintaining state across requests then this option is best. Creating our own singleton behavior is not recommended.

It provides two important flavors.

  1. First where we let the framework to create the instance as
    services.AddSingleton<ITestService, TestService>();
    
  2. Second where we create the instance and register the same instance as
    ITestService testService = new TestService();
    services.AddSingleton(testService);
    

    So if we have some custom heavy object that can be used across request or do some changes in the instance before registering then second option is good.

Now let’s run the application
addsingelton
Here we get the same instance across multiple requests.

Third party DI containers

For basic usages of DI, we can use the default DI container but for the advance usage, we can use any third part DI container with the ASP.NET like Autofac, Unity, Ninject etc or some custom one. For that we need to have an adapter which provides implementation of IServiceProvider or we can write our own. We have already the required implementation for Autofac which can be easily integrated. let’s see that.

Using Autofac with ASP.NET

It’s very simple to leverage to use the power of Autofac. We need to include the following package in our project.

Autofac.Extensions.DependencyInjection

Once that is added, we need to make few changes in ConfigureServices Method. By default, it returns void but to use other provider, it should return IServiceProvider. We will create the instance of ContainerBuilder then register our services. Then get the container and return the service provider from the context.

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            var builder = new ContainerBuilder();
            builder.RegisterType<TestService>().As<ITestService>().InstancePerLifetimeScope();
            builder.Populate(services);
            var container = builder.Build();
            return container.Resolve<IServiceProvider>();
        }

Here we can see that we provided the life time of the instance while registering the service similar to AddScoped. We can also see that we used default container to add mvc, it means we can mix and match with containers.

Final words

Dependency Injection is very helpful for writing loosely coupled and testable software. Its usage with earlier versions of ASP.NET was bit tricky but with the new version ASP.NET, It has become the first-class citizen of ASP.NET Stack. We have seen that it provides a basic DI container and discussed with an example with details. Also, we discussed that how we can configure other third party containers like Ninject, Autofac, unity etc. We have configured Autofac in our example and saw we can use multiple container in same application.

Advertisements

Learning ASP.NET Web API [Packt] – ASP.NET Core RC1 to ASP.NET Core 1.0

Hello All,

Recently, I published a video course on ASP.NET Web API using ASP.NET Core framework. Initially, when I started working on it, it was named as ASP.NET 5 and as it progressed till last section, Microsoft announced to rename it as ASP.NET Core and RC2 got released few days prior to the course release date. Microsoft took more than six months to release the next RC version. Although the concept was same but there were major changes in tooling and libraries. As it was not the final version so we decided to provide the details of differences once RTM releases.

In this post, I will be putting the details of the changes by section and also update the sample which will be available with the course. As ASP.NET 5 got renamed to ASP.NET Core, accordingly the names of libraries got changed to ASP.NET Core as well so we need to change all the references. The following table contains the details of packages that we need to update in our sample with the video number.

ASP.NET 5 Reference (Earlier) ASP.NET Core 1.0 Reference (Current) Video#
Microsoft.AspNet.Mvc Microsoft.ASPNETCore.MVC 2.2
EntityFramework.Core
EntityFramework.MicrosoftSqlServer
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
2.3
Microsoft.AspNet.Mvc.Formatters.Xml Microsoft.AspNetCore.Mvc.Formatters.Xml 2.4
Microsoft.AspNet.Mvc.TagHelpers
Microsoft.AspNet.Identity.EntityFramework
Microsoft.AspNetCore.Mvc.TagHelpers
Microsoft.AspNetCore.Identity.EntityFrameworkCore
5.4

Updated sample is available with the course and refer the project.json to find the updated references. Also, Microsoft again reintroduced web.config file but it will be there along with Project.json.

Note – The details will be included for only for those those sections where changes are required.

Section 2   
As this was the first section where we started our discussion on ASP.NET Core Web API and started working on our sample so this section got many changes. Let’s discuss each

Video 2.1 : There are changes in the project creation flow. Earlier when we used to create ASP.NET Core project, it used to have two sets of references – one for core and other for full framework. We either used to build the application using both the framework and remove one based on our needs. As there were many libraries which could not work in both the platforms so Microsoft has provided the option to select the framework upfront while creating the project which makes the complete process simpler. Also, in real world scenarios, there are rare chances when we need to build the binaries for both the framework.  Now when we open New Project window and select web from left side then we get three options as
2.1Here we have three options.

  1. First one is a traditional ASP.NET application using .NET 4.6.
  2. Selected one is ASP.NET Core application using .NET Core framework and the same is used in our course.
  3. Third one is again ASP.NET Core application but uses the standard .NET framework.

When we select the second option, it shows the following dialog

2.1_2

It also got revamped completely. We had earlier lots of options which included standard ASP.NET templates. Now it contains only ASP.NET Core templates and has three options same as earlier ASP.NET 5 templates and we used the empty template for our course. Just to mention again, now we have just one bag named as .NETCoreApp,Version=v1.0  which contains set of libraries for .NET Core only in the references.

There are some more changes as below

a) Earlier we used to have following line in startup.cs which was entry point for the web application

// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);

but now we have a new file program.cs which contains the main method which is now entry point for the web application.

b) Configuration file web.config is also back in project file and available along with project.json although all the settings should be put in project.json and we will be using the same.

c) There are also changes in the number of the parameters in ConfigureServices method in startup.cs which includes Hosting Environment and logger factory but we will not be using it in our sample.

Video 2.2: Only change in the references. Refer the initial table.

Video 2.3: In this video, we discussed that there are four options to register a service but we found AddSingleton and AddInstance very similar, both allows single instance across multiple requests with a difference in the instance creation. Now we have only AddSingleton where either we can pass the instance or provide the type info as.

To register via interface and class name

services.AddSingleton<IBookStoreRepository, BookStoreRepository>();

and to register an instance

IBookStoreRepository bookStoreRepository = new BookStoreRepository(new BookStoreContext());
services.AddSingleton(bookStoreRepository);

Video 2.4: Only change in the references. Refer the table.

Section 3
In this section we added CRUD operations to our sample using  HTTP verbs. Only few changes are required in the section as mentioned below.

Video 3.2: Microsoft did an awesome change with it by making the JSON response in camel case by default. In our sample we added serialize settings in statrtup.cs as

options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

It is no more required.

Video 3.3 :  We returned various status codes from the action methods based on the request.The classes that we used also got renamed as

ASP.NET 5 ASP.NET Core 1.0
HttpUnauthorized Unauthorized
HttpNotFound (and its overloads) NotFound
HttpBadRequest (and its overloads) BadRequest

The above changes has taken place in all the action methods wherever used.

Section 4 
In this section, we added few more features to our sample like sorting, paging etc. Here there is a change in the way we access URL Helper as discussed below.

Video 4.3: We used URL helper for generating the URLs and it was injected via constructor without any other changes as it was by default available which is not the case now.

Now we need to access it via UrlHelperFactory and action context. ActionContext is accessed via ActionContextAccessor, for that we need to register it in startup.cs as

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

and we need to inject the UrlHelperFactory and ActionContextAccessor in constructor to get the URL helper as

  public BooksController(IBookStoreRepository _repository, IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)
        {
            this.repository = _repository;
            this.urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);
        }

Rest of the code would be same as we got the similar URL helper.

Section 5
In this section we talked about security implementation. In it we have only few changes as below.

Video 5.2 : We created a custom authorization attribute RequireHttpsAttribute which inherited from AuthorizationFilterAttribute where we checked the scheme from the URL. Now RequireHttpsAttribute is itself available under the namespace Microsoft.AspNetCore.Mvc so we can use the same to enforce the SSL in complete application or any specific controller/action.

Video 5.4 : Only few references changes. Refer the table

Section 6 
In this section, we discussed some advanced topics like DI, CORS etc and there are few changes in DI. Let’s see that

Video 6.1:
a) As discussed earlier that now we don’t have AddInstance option for registering the service, same can be achieved via AddSingleton.

b) We discussed that we can also inject services via property using FromServices attribute but it is not available any more as it was creating confusion and issues. Constructor injection is always preferable. From services is available and can be used for Action Injection as

public IEnumerable<Book> Get([FromServices] IBookStoreRepository repository)
{
...
}

These are the key changes that took place specific to Web API and our course. I created again the sample from scratch using the ASP.NET Core 1.0 which can be downloaded from the course.

Thanks a lot for your support and feedback.

Cheers
Brij