Dependency Injection in ASP.NET Core

Dependency Injection in ASP.NET Core

Dependency Injection (DI) is an ASP.NET Core MVC technique to achieve loosely coupling between objects.

The working of the Dependency Injection is like:

If a Controller has a dependency on another class, then in the constructor of the Controller the dependency for the class is defined. On seeing this dependency the Core MVC provides the class object to the Controller automatically. So this provides loosely coupling between the Controller and the other class.

Create the Example Project

For this DI tutorial, create an ASP.NET Core Web Application project and then select Empty Project Template and name it DependencyInjection. Remember to select the framework as .NET Core and version as ASP.NET Core 3.1.

Model & Repository

Create Models folder in the root of the project and add a class called Product with codes shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class Product
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

Next create a new class file and call it IRepository, add it inside the Models folder. Define an Interface in it whose code is given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public interface IRepository
    {
        IEnumerable<Product> Products { get; }
 
        Product this[string name] { get; }
 
        void AddProduct(Product product);
 
        void DeleteProduct(Product product);
    }
}

This interface will be implemented in another class called Repository. So create Repository.cs inside the Models folder and add the following code to it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class Repository : IRepository
    {
        private Dictionary<string, Product> products;
        public Repository()
        {
            products = new Dictionary<string, Product>();
            new List<Product> {
                new Product { Name = "Women Shoes", Price = 99M },
                new Product { Name = "Skirts", Price = 29.99M },
                new Product { Name = "Pants", Price = 40.5M }
            }.ForEach(p => AddProduct(p));
        }
 
        public IEnumerable<Product> Products => products.Values;
        public Product this[string name] => products[name];
        public void AddProduct(Product product) => products[product.Name] = product;
        public void DeleteProduct(Product product) => products.Remove(product.Name);
    }
}

Since I don’t want to fetch the products from the database for this tutorial therefore I am creating some products that will be kept in the Memory.

This is done by the constructor of the Repository class that initializes a new dictionary of products and adds 3 products to this dictionary.

Configuration

Go to the Startup.cs class and add the necessary services and configurations inside the ConfigureServices() and Configure() methods as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace DependencyInjection
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Controller

Create Controllers folder in the root of the project and add a new controller called HomeController to it. The code of this controller is given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DependencyInjection.Models;
using Microsoft.AspNetCore.Mvc;
 
namespace DependencyInjection.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View(new Repository().Products);
        }
    }
}

You can see clearly that in the Index Action Method I am creating a new object of the Repository class and calling its Products property. This property contains all the products. Then finally returning this property to the View.

My Home Controller is dependent on the Repository class in a Tightly Coupled way. I will now use the Dependency Injection technique to make them Loosely Coupled.

Install Bootstrap Package

I will be using Bootstrap package for making the UI look good. You can use LibMan or Bower to install Bootstrap package in Visual Studio.

Make sure to install Bootstrap inside the wwwroot ➤ lib folder.

_ViewImports.cshtml

Create Views folder in the root of the application and to it add _ViewImports.cshtml file.

Adding _ViewImports.cshtml is simple, just right click on the Views folder and select Add ➤ New Item. In the Add New Item window search for View Imports.

Add the following following code to the _ViewImports.cshtml file:

Add View Imports
@using DependencyInjection.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

The purpose of _ViewImports.cshtml file is to provide namespaces which can be used by all other views. It also includes the ASP.NET Core Built-In TagHelpers in the application.

Views

Add Index view inside the Views ➤ Home folder with codes given below:

@model IEnumerable<Product>
@{ Layout = null; }
 
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Dependency Injection</title>
    <link rel="stylesheet" asp-href-include="lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body class="m-1 p-1">
    @if (ViewData.Count > 0)
    {
        <table class="table table-bordered table-sm table-striped">
            @foreach (var kvp in ViewData)
            {
                <tr><td>@kvp.Key</td><td>@kvp.Value</td></tr>
            }
        </table>
    }
    <table class="table table-bordered table-sm table-striped">
        <thead>
            <tr><th>Name</th><th>Price</th></tr>
        </thead>
        <tbody>
            @if (Model == null)
            {
                <tr><td colspan="3" class="text-center">No Model Data</td></tr>
            }
            else
            {
                @foreach (var p in Model)
                {
                    <tr>
                        <td>@p.Name</td>
                        <td>@string.Format("{0:C2}", p.Price)</td>
                    </tr>
                }
            }
        </tbody>
    </table>
</body>
</html>

This View takes a model of type IEnumerable type as the Index action returns all the products in IEnumerable manner. This View will show all the Products in a HTML table.

Run your application and you will see all the 3 products as shown by the image given below:

tightly couple example

Tightly Coupled Controller

If you see the Controllers code you will find it is Tightly Coupled to the Repository class. The reason being to create the object of Repository class in order to return the products to the View:

return View(new Repository().Products); 

Tightly Coupled components are bad programming practices since they cause:

  • 1. Problems in maintenance of the project – because if one component changes then it will affect the other component too.
  • 2. Problems in performing Unit Testing of the components.

Suppose after some time you need to show some other products that are listed in another class (eg NewRepository). In that case you have to make changes to your Controller’s Index action like this:

public IActionResult Index()
{
    return View(new NewRepository().Products);
}

This practise is not a good one.

The best practice would be the Home Controller class should not have any knowledge about which class product class to use or how the class is instantiated. And this will be achieved through Dependency Injection (DI).

Implementing Dependency Injection into controllers

ASP.NET Core makes Implementing Dependency Injection (DI) very easy to apply. In this section you will learn implementing DI into ASP.NET Core Controllers.

To do this the Repository Class must implement an Interface whose work would be to decouple the system. Then use this Interface (instead of the Repository class) in the Home Controller. Note that I have already done this and in my case it is the IRepository interface.

public class Repository: IRepository
{
}

After that do 2 things:

  • 1. Add a variable of the Interface type (i.e IRepository) in your controller.
  • 2. Add a constructor that has a parameter of this interface. Inside the constructor you set the value of the interface variable to the value of the parameter.

Now in your action method you can access the products using the interface itself.

These 2 steps are given in the updated Home Controller code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DependencyInjection.Models;
using Microsoft.AspNetCore.Mvc;
 
namespace DependencyInjection.Controllers
{
    public class HomeController : Controller
    {
        private IRepository repository;
        public HomeController(IRepository repo)
        {
            repository = repo;
        }
 
        public IActionResult Index()
        {
            return View(repository.Products);
        }
    }
}

Now you have to tell the application how it should resolve the dependency of IRepository interface. So go the Startup class and inside the ConfigureServices() method, add the code line that is highlighted below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IRepository, Repository>();
    services.AddControllersWithViews();
}

I used the AddTransient() method that tells the service provider how to handle a dependency, the first type being the interface (here IRepository) while the second type being the implementation class (here Repository).

Now you rerun your application, and you will see the products are displayed just like below, but here you used Dependency Injection to lightly-couple the Controller and the Repository class.

Suppose at a later time you need to show products from another class called NewRepository.cs. So now you just need to change the AddTransient method to – services.AddTransient<IRepository, NewRepository>();.

The below image illustrates the concept of Dependency Injection:

dependency injection
Advantage of DI

With DI it is very easy to do changes. Example the code – services.AddTransient<IRepository, NewRepository>(); says if there is a dependency of IRepository object then resolve it with NewRepository object.

You don’t have to do any change in the Home Controller, that is all because the Loosely Coupled Components created from DI.

Congratulations you have successfully used Dependency Injection technique in your project. Now I will introduce you to other aspects of DI.

Resolving Dependency Chains

The meaning of Dependency Chains is – the Dependency itself has a dependency on another component. For example if a Component ‘Alpha’ has a dependency on another Component called ‘Beta’, while Beta has a dependency on Component called ‘Gamma’. Then this becomes a Dependency Chain.

Dependency Injection feature of ASP.NET Core is very intelligent to resolve the Dependency Chain. Let me explain you with an example.

Add a class file called IStorage.cs to the Models folder and use it to define the interface shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public interface IStorage
    {
        IEnumerable<Product> Items { get; }
        Product this[string key] { get; set; }
        bool ContainsKey(string key);
        void RemoveItem(string key);
    }
}

Now implement this interface in a new class called Storage.cs which should be added to the Models folder. The code of the Storage.cs class is given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class Storage : IStorage
    {
        private Dictionary<string, Product> items = new Dictionary<string, Product>();
        public Product this[string key]
        {
            get { return items[key]; }
            set { items[key] = value; }
        }
        public IEnumerable<Product> Items => items.Values;
        public bool ContainsKey(string key) => items.ContainsKey(key);
        public void RemoveItem(string key) => items.Remove(key);
    }
}

The Storage class defines the behaviour of a simple storage mechanism for Product objects.

Now go to your previously created Repository.cs class and create a dependency on IStorage interface. For doing this add an argument of IStorage type in the constructor of the Repository.cs class.

Next change all the methods and properties which now work with the IStorage object, like what is shown in the updated code for the Repository class below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class Repository : IRepository
    {
        private IStorage storage;
        public Repository(IStorage repo)
        {
            storage = repo;
            new List<Product> {
                new Product { Name = "Women Shoes", Price = 99M },
                new Product { Name = "Skirts", Price = 29.99M },
                new Product { Name = "Pants", Price = 40.5M }
            }.ForEach(p => AddProduct(p));
        }
 
        public IEnumerable<Product> Products => storage.Items;
 
        public Product this[string name] => storage[name];
 
        public void AddProduct(Product product) => storage[product.Name] = product;
 
        public void DeleteProduct(Product product) => storage.RemoveItem(product.Name);
    }
}

With these changes you have created a Dependency Chain as:

  • 1. Home Controller Class depends upon IRepository object.
  • 2. IRepository object in turn depends upon IStorage object.

Now all I have to do is to tell the Service provider how to resolve this Dependency Chain. So go to the Startup.cs class and add the code line (services.AddTransient<IStorage, Storage>()) inside the ConfigureServices() method as shown below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IRepository, Repository>();
    services.AddTransient<IStorage, Storage>();
    services.AddControllersWithViews();
}

Rerun your application and you will see all your products displayed in the browser just like before.

dependency chains example

The only difference is that here you resolved the Dependency Chains.

Do you know that Startup class can be used to perform hundreds of configurations in your app. You can read Configuring Application in ASP.NET Core where I have covered all this from start to finish.

Dependency Injection for Single Type

If you have a simple class that does not implement an Interface then it is a Single Type. In such a case you can use the Dependency Injection technique.

Create a new class called ProductSum.cs to the Models folder and add the below listed code to it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class ProductSum
    {
        public IRepository Repository { get; set; }
        public ProductSum(IRepository repo)
        {
            Repository = repo;
        }
         
        public decimal Total => Repository.Products.Sum(p => p.Price);
    }
}

Note that this class does not implement any interface. It simply has a property called Total that returns a sum of all the products of the Repository class.

The class has a dependency on IRepository interface and will be resolved by the service provider due to the configuration which I have already applied on the ConfigureServices() method.

Now in your Home Controller, you create a dependency for this ProductSum class in the Constructor and set a ViewBag variable that contains the sum of all the products. This ViewBag variables will be shown in the View.

The updated code for the Home controller is shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DependencyInjection.Models;
using Microsoft.AspNetCore.Mvc;
 
namespace DependencyInjection.Controllers
{
    public class HomeController : Controller
    {
        private IRepository repository;
        private ProductSum productSum;
        public HomeController(IRepository repo, ProductSum psum)
        {
            repository = repo;
            productSum = psum;
        }
 
        public IActionResult Index()
        {
            ViewBag.Total = productSum.Total;
            return View(repository.Products);
        }
    }
}

Now configure the service provider telling it how to resolve this new dependency. So add the following code line – services.AddTransient<ProductSum>() in the ConfigureServices() method:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IRepository, Repository>();
    services.AddTransient<IStorage, Storage>();
    services.AddTransient<ProductSum>();
    services.AddControllersWithViews();
}

Note that there is no mapping between a service type and an implementation type in this situation. I have used the AddTransient() method with only one parameter. In this way I tell the service provider to initiate the ProductSum class to resolve a dependency on this type. This is Dependency Injection for Single Type.

Run your application and you will see the total price of all the products displayed on the browser:

dependency injection for Single Type

Dependency Injection Methods

You have already seen the AddTransient() Dependency Injection Method. There are also 2 other methods – AddScoped() and AddSingleton methods.

1. AddTransient

The AddTransient method creates a new instance of the Implementation type every time it resolves a dependency.

2. AddScoped

The AddScoped method does not always create a new instance of the implementation class. It reuses instance of the Implementation type for the request arising from same HTTP. That is it shares the same object.

3. AddSingleton

The AddSingleton method creates a new instance of the implementation type for the first request only. It then reuses it for every subsequent request.

There are 3 variations each for AddTransient, AddScoped & AddSingleton methods:
1. <service, implType>()

This variation creates an instance of the implementation type for every dependency. In the above explained section called Implementing Dependency Injection (DI) I have already used this variation.

2. <service>()

This variation is used to register a Single Type object. In the above section called Dependency Injection for Single Type I have already used this variation.

3. <service>(factoryFunc)

This variation is used to register a factory function that will be invoked to create implementation objects. I will implement this variation in the later end of the tutorial.

Using AddTransient Method

The AddTransient() method tells the service provider to create a new instance of the implementation type every time it resolves a dependency.

I have had the AddTransient methods already there in my Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IRepository, Repository>();
    services.AddTransient<IStorage, Storage>();
    services.AddTransient<ProductSum>();
    services.AddControllersWithViews();
}

For the Repository class there are 2 things to note:

  • 1. See the constructor of the Home controller where you will find it has a dependency on the IRepository and ProductSum. public HomeController(IRepository repo, ProductSum psum) { ... }
  • 2. The ProductSum class has a dependency on the IRepository. public ProductSum(IRepository repo) { ... }

The service provider will create 2 instances of the Repository since I am using the AddTransient() method. One instance will be created to resolve the dependency of the Home Controller and other to resolve the dependency of ProductSum class.

Next in the Repository.cs class, add an override of the ToString() method, that returns a new GUID as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class Repository : IRepository
    {
        // ...
        private string guid = System.Guid.NewGuid().ToString();
        public override string ToString()
        {
            return guid;
        }
    }
}

The GUID value will help to identify the specific instance of the Repository.cs class.

Next go to the Home Controller and in it’s Index action and adds 2 ViewBag variables. First ViewBag variable will contain the GUID received from the Repository class object while the Second ViewBag variable contains the GUID received from the ProductSum class object.

The updated code is shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DependencyInjection.Models;
using Microsoft.AspNetCore.Mvc;
 
namespace DependencyInjection.Controllers
{
    public class HomeController : Controller
    {
        // Removed for clarity
 
        public IActionResult Index()
        {
            // ViewBag.Total = productSum.Total;
            ViewBag.HomeControllerGuid = repository.ToString();
            ViewBag.TotalGuid = productSum.Repository.ToString();
            return View(repository.Products);
        }
    }
}

Now run your application and you will see the GUID values from 2 ViewBag variables are different. This specifies that the service provider has created 2 instances of the Repository class.

My article on ASP.NET Core Views covers all about ViewBag variables. Do also read it.

This image below shows the different values of the GUIDs:

dependency injection through addtransient method

Using AddScoped Method

The AddScoped method does not always create a new instance of the implementation class. It reuses instance of the Implementation type for the request arising from the same HTTP requests i.e. shares the same object among those requests.

The AddScoped() method will tell the service provider to share the single object for all the components that process a request.

Go to the ConfigureServices() method of the Startup class and change the AddTransient method to AddScoped for the IRepository object.

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IRepository, Repository>();
    services.AddTransient<IStorage, Storage>();
    services.AddTransient<ProductSum>();
    services.AddControllersWithViews();
}

Rerun your application and you will see the both GUIDS have the same value. This means the Service Provider has created only one object of the Repository class which is shared between the ‘Home Controller’ and the ‘ProductSum’ class.

Reload the page and you will see new Guid is generated, because a new HTTP request is initiated and so a new object to the Repository class is created.

The below image illustrates this thing with red markings:

dependency injection through addscoped method

Using AddSingleton Method

The AddSingleton() method tells the Service Provider to ensure only a single object is used for all requests for a given type.

Go to ConfigureServices() method and use the AddSingleton() method to resolve the dependency of type IRepository:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IRepository, Repository>();
    services.AddTransient<IStorage, Storage>();
    services.AddTransient<ProductSum>();
    services.AddControllersWithViews();
}

Rerun your application and you will see both the GUID values are same, refresh the page but you will notice the GUID values do not changes.

See the image below which illustrates it:

dependency injection through addsingleton method

The AddSingleton method creates a new instance of the Repository class the first time only and it is shared on for each and every request.

Action Injection with FromServices

Declaring dependency through a constructor of the Controller can be expensive because the dependency is resolved every time the Controller is created, and also because not all action methods need the implementation type object.

So here comes the part of Action Injection dependency which is declared through the parameters of Action methods. So only the particular action method causes the implementation type to initiate. This means the dependency is not resolved on every time the Controller is called.

In Action Injection the [FromServices] attribute is applied to the parameters.

In the home controller change the Index Action method to include a parameter of ProductSum type and add [FromServices] attribute to it. Also remove the ProductSum attribute from the constructor of the controller.

The updated code is given below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DependencyInjection.Models;
using Microsoft.AspNetCore.Mvc;
 
namespace DependencyInjection.Controllers
{
    public class HomeController : Controller
    {
        private IRepository repository;
        public HomeController(IRepository repo)
        {
            repository = repo;
        }
 
        public IActionResult Index([FromServices] ProductSum productSum)
        {
            // ViewBag.Total = productSum.Total;
            ViewBag.HomeControllerGuid = repository.ToString();
            ViewBag.TotalGuid = productSum.Repository.ToString();
            return View(repository.Products);
        }
    }
}

Now the ProductSum type will be resolved only when the Index Action Method is invoked and not when Controller is invoked.

Using a Factory Function (factoryFunc)

This Factory Function (factoryFunc) variation is used to register a factory function that will be invoked to create implementation objects. So you can use it to create your own logic to tell the application when to resolve the dependencies. Let us create a small example to understand it.

Create a new class called NewRepository.cs inside the Models folder and add the following code to it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace DependencyInjection.Models
{
    public class NewRepository : IRepository
    {
        private Dictionary<string, Product> products;
 
        public NewRepository()
        {
            products = new Dictionary<string, Product>();
            new List<Product> {
                new Product { Name = "Women Shoes", Price = 99M },
                new Product { Name = "Skirts", Price = 29.99M },
                new Product { Name = "Pants", Price = 40.5M }
            }.ForEach(p => AddProduct(p));
        }
 
        public IEnumerable<Product> Products => products.Values;
        public Product this[string name] => products[name];
        public void AddProduct(Product product) => products[product.Name] = product;
        public void DeleteProduct(Product product) => products.Remove(product.Name);
    }
}

Now go to the Startup class and add the Factory function to resolve the dependency of IRepository. This factory function is added inside the ConfigureServices method and is given below:

public class Startup
{
    private IWebHostEnvironment env;
    public Startup(IWebHostEnvironment hostEnv) => env = hostEnv;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<IRepository>(provider =>
        {
            if (env.IsDevelopment())
            {
                var x = provider.GetService<Repository>();
                return x;
            }
            else
            {
                return new NewRepository();
            }
        });
        services.AddTransient<Repository>();

        services.AddTransient<IStorage, Storage>();
        services.AddTransient<ProductSum>();
        services.AddControllersWithViews();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ...
    }
}

The code checks if the environment is development then creates a new instance of Repository class else a new instance of NewRepository class is created.

Notice that in order for the ConfigureServices method to access the environment you have to add a constructor for the Statup class. This constructor must have a parameter of type IWebHostEnvironment.

private IWebHostEnvironment env;
public Startup(IWebHostEnvironment hostEnv) => env = hostEnv;

Injecting Values from JSON file to Controllers

By using the Dependency Injection feature you can also inject values from a JSON file to a controller or View. Let me show how to perform this task.

Create a JSON file on the root of the project and name it mysettings.json. Then add the following content to this file:

{
    "Title": "Dependency Injection Tutorial",
    "Version": 3
}

Next Configure the app to read the settings from a JSON formatted file. You do this by commenting the CreateHostBuilder function of the Program.cs class and adding the below given implementation of the function.

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace DependencyInjection
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddJsonFile("mysettings.json",
                                optional: false,        // File is not optional.
                                reloadOnChange: false);
        })
        .UseStartup<Startup>();
    }
}

The AddJsonFile method used here will add the JSON file to the IWebHostBuilder.

You will also need to create a class that will store the values from the mysettings.json file after it has been read. So create a class called MyJson.cs in the Models folder and add the following properties to it.

public class MyJson
{
    public string Title { get; set; }
    public int Version { get; set; }
}

Finally add the MyJson.cs class to the services collection in the Startup.cs class. You have to do 3 things in the Startup class:

  • 1. Include the namespace called Microsoft.Extensions.Configuration
  • 2. Add a property of type IConfiguration and provided it with value through DI in the constructor of startup class.
  • 3. Add the configuration class to the services collection.

In the below code I have marked all these 3 things.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using DependencyInjection.Models;
using Microsoft.Extensions.Configuration;

namespace DependencyInjection
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<MyJson>(Configuration);
            services.AddControllersWithViews();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //...
        }
    }
}

You are now ready to read the values from JSON file in any Controller or View. So create a controller and name it SettingsController.cs. In this controller add a contructor that takes IOptions<MyJson> type parameter. This parameter will be provided with the value from the JSON file by Dependency Injection automatically. The code is given below:

using DependencyInjection.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DependencyInjection.Controllers
{
    public class SettingsController : Controller
    {
        private readonly MyJson _settings;
        public SettingsController(IOptions<MyJson> settingsOptions)
        {
            _settings = settingsOptions.Value;
        }

        public IActionResult Index()
        {
            ViewData["Title"] = _settings.Title;
            ViewData["Version"] = _settings.Version;
            return View();
        }
    }
}

Notice I have added an Index action where I am providing the values from settingsOptions variable to the 2 ViewData variables. Now all I have to do is to show these values in the View.

So add Index view in the Views ➤ Settings folder and add the following code to it:

[email protected]{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Dependency Injection</title>
    <link rel="stylesheet" asp-href-include="lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body class="m-1 p-1">
    @if (ViewData.Count > 0)
    {
        <table class="table table-bordered table-sm table-striped">
            @foreach (var kvp in ViewData)
            {
                <tr><td>@kvp.Key</td><td>@kvp.Value</td></tr>
            }
        </table>
    }
</body>
</html>

The view only shows the values contained in 2 ViewData variables.

Run your application and go to the URL – https://localhost:44301/Settings where you will find the values from the JSON file being displayed. See the below screenshot.

Injecting Values from JSON file

Dependency injection into Views

ASP.NET Core supports Dependency Injection into Views using the @inject directive. I will give 2 examples to understand this thing.

The power of filters are like those of Thanos – Learn to use Filters in ASP.NET core from beginning to expert level
1. Injecting Values from JSON file

Just like what I did in the above topic – Injecting Values from JSON file to Controllers. This time I will inject mysettings.json file values to the View directly.

Note that I have already done the configuration part for this JSON file in Startup.cs & Program.cs. Now all I have to perform the injection part.

So add a new action called Show to the SettingsController.

public IActionResult Show()
{
    return View();
}

Next go to the Show view and add the necessary namespaces followed by the @inject directive to inject the IOptions type which contains the values of the mysettings.json file.

@using Microsoft.Extensions.Options;
@using DependencyInjection.Models;
@inject IOptions<MyJson> settingsOptions

Finally show these values in the View using the code:

@settingsOptions.Value.Title
@settingsOptions.Value.Version

Below is the full code for the View.

@{
    Layout = null;
}

@using Microsoft.Extensions.Options;
@using DependencyInjection.Models;
@inject IOptions<MyJson> settingsOptions

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Dependency Injection</title>
    <link rel="stylesheet" asp-href-include="lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body class="m-1 p-1">
    <table class="table table-bordered table-sm table-striped">
        <tr>
            <td>Title</td>
            <td>@settingsOptions.Value.Title</td>
        </tr>
        <tr>
            <td>Version</td>
            <td>@settingsOptions.Value.Version</td>
        </tr>
    </table>
</body>
</html>

Run your application and go to the URL – https://localhost:44301/Settings/Show. You will see the values displayed on the view (see below image).

Injecting Values from JSON file
2. Configuration injection (appsettings.json)

The appsettings.json values can be injected directly into a view. It is a very simple procedure where all you have to do is use the inject directive and then show the values. This is shown in the below code.

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<div>@Configuration["Logging:LogLevel:Default"]</div>

Let me create an example. My application’s appsettings.json file has the below given values which I have to show in a View.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

I will show the values for the nodes – Default, Microsoft & Microsoft.Hosting.Lifetime.

Head to the SettingsController and add a View called Detail. Just add the following code to this View and you are all done.

@{
    Layout = null;
}

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Dependency Injection</title>
    <link rel="stylesheet" asp-href-include="lib/twitter-bootstrap/css/bootstrap.css" />
</head>
<body class="m-1 p-1">
    <table class="table table-bordered table-sm table-striped">
        <tr>
            <td>Default</td>
            <td>@Configuration["Logging:LogLevel:Default"]</td>
        </tr>
        <tr>
            <td>Microsoft</td>
            <td>@Configuration["Logging:LogLevel:Microsoft"]</td>
        </tr>
        <tr>
            <td>Microsoft.Hosting.Lifetime</td>
            <td>@Configuration["Logging:LogLevel:Microsoft.Hosting.Lifetime"]</td>
        </tr>
    </table>
</body>
</html>

Test it by going to the URL – https://localhost:44301/Settings/Detail. You will see the appsettings.json values getting displayed as shown by the image below.

configuration injection to views

You can download the full codes of this tutorial from the below link:

Download

Conclusion

In this tutorial I explained working with Dependency Injection feature which is a new addition in the ASP.NET Core MVC framework. I hope you find it useful.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.