Your Dependency Injection ready ASP.NET : ASP.NET 5


Dependency Injection has become one the key design patterns of the current projects. It helps in writing loosely coupled code which makes the code easily testable and maintainable. As per wiki

Dependency injection is a software design pattern that implements inversion of control for software libraries. Caller delegates to an external framework the control flow of discovering and importing a service or software module specified or “injected” by the caller.

In this post, we will see that how easily we can implement this pattern with ASP.NET 5 projects and leverage various available options .

ASP.NET 5 got completely redesigned and made DI friendly. It provides a by default container which can be used while writing the application. It also enables us to use third party containers with it and you may need a adapter to use with ASP.NET.

In ASP.NET 5, there is a new file added with the name startup.cs, which is the entry point of your ASP.NET application. It has two methods

1- public void ConfigureServices(IServiceCollection services)

2- public void Configure(IApplicationBuilder app)

ConfigureServices is a global method where all the services should be registered. Then all these services are available through out the application. Let’s first see that what all methods are available

DIOptionsNow let’s discuss one by one.

AddTransient – Registering a service via this method will create a new service instance each time accessed. Let’s see it via an example.

In this example, I have created a simple MVC application from an ASP.NET 5 Empty Project. Added on HomeController and Index view. I created a Repository as follows

    public interface IRepository
    {
        int GetnUpdateCounter();
    }
    public class MyRepository : IRepository
    {
        private int i;
        public int GetnUpdateCounter()
        {
            return i++;
        }
    }

In the above repository, I have a private integer variable which I am updating and returning via the method. This repository I will be using two or more places to show you the behavior. I have used it in my HomeController as

    public class HomeController : Controller
    {
        [Activate]
        public IRepository myRepository { get; set; }
        // GET: /<controller>/
        public IActionResult Index()
        {
            ViewBag.Counter = myRepository.GetnUpdateCounter();
            return View();
        }
    }

I also created a custom tag helper (To learn about Tag helper in detail – Click here) as

    public class TestTagHelper : TagHelper
    {
        [Activate]
        public IRepository MyTalkRepository { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "h5";
            output.Content = "From TagHelper - " + MyTalkRepository.GetnUpdateCounter().ToString();
        }
    }

In the tag helper above, I am using the Repository again and displaying it in an element. This tag helper is used in the Index View. My Index view looks like

@addtaghelper "DI"

<div style="font-family:Verdana; font-size:small">
	<h2>Dependency Injection demo</h2>
    <h3>@ViewBag.Counter</h3>
    <test></test>
</div>

Now in the above view, I am showing the counter which I got it from Repository which is injected in HomeController.

The Repository is added in StartUp file as

public void ConfigureServices(IServiceCollection services)
{
    <strong> services.AddTransient<IRepository, MyRepository>();</strong>
     services.AddMvc();
}

Here I used AddTransient to register the Repository. Now let us run this code

TransientWe can see here that we see 0 at both places. It means there are two instances get created for the repository as expected.

AddScoped – Registering a service via this method can be really useful if we want to use the same instance while processing a particular request. Say we are using the service at two places as above – one in Taghelper and other in controller. The same instance will be available. Let’s see it via an example

All the above code would be same, the only change would be the way we register in ConfigureServices method as

public void ConfigureServices(IServiceCollection services)
{
    <strong>services.AddScoped<IRepository, MyRepository>();</strong>
    services.AddMvc();
}

Here I used AddScoped. Lets run the code again

ScopedFrom the above screen, we can say that in a request, same instance of repository is used because here the counter is maintaining the state.

AddSingleton – As the name suggests, here on first request the instance of Repostory is created and the same will be used in across all requests. Let’s change the code for registering it as

Singleton

Here we can see that state is maintained across multiple request.

AddInstance – This is similar to AddSingleton but the only difference is here that here the responsibility to create the instance is upto the developer.So lets create the instance and add that in Startup.cs as

private IRepository myRepositoy;
public Startup()
{
	myRepositoy = new MyRepository();
	myRepositoy.GetnUpdateCounter();
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddInstance(myRepositoy);
    services.AddMvc();
}

Here I created the instance in constructor and added the instance.I purpose fully called the method in constructor to change the state of repository instance. Now lets run the code

Instance

Here we can see that the same instance (with same state) is used in across requests.

One of the classic example of this scenario would be a to create Configuration object.

Note – For the sample, Visual Studio 2015 CTP6 is used. In final release the feature may get changed slightly.

In this post, we discussed the default DI container available with ASP.NET 5. Demo is attached with this post. I created different folder named startupfiles which contains the startup.cs for all four scenarios. Use those files as we discussed to run each scenario.

Hope you have enjoyed the post.

Cheers,
Brij

Leave a comment