Written by Mark Pringle | Last Updated on Friday, January 06, 2023

C# Programming ASP.NET Version: 6.0 General Information

If you are researching dependency injection, no doubt you have already watched hour-long videos or read most multipage documents that attempt to explain dependency injection. However, I will keep my explanation short and sweet since the name “dependency injection” tells us what this coding technique does.

Dependency injection is a process in which we provide or inject an instance of a class into another class or object. Dependency injection allows a class you create to take advantage of another class’s constructors, fields, methods, properties, etc., by injecting that class and all of its associated capabilities into the dependent class you create or are using. For instance, suppose Class A needs Class B to do something. That means Class B is a dependency of Class A and Class A has all of the "power" of Class A and Class B.

With dependency injection, classes can even take advantage of deeply nested dependencies. For instance, suppose Class A needs Class B to do something, and Class B uses Class C to do something. That means Class C is a dependency of Class B and Class B is a dependency of Class A. So, Class A has all of the "power" of Class A, Class B, and Class C. 

What Dependency Injection Looks Like in ASP.NET MVC C#

The LearnASPNET website uses a HomeController class that houses our web application's action methods for various views (pages). The example below shows that the HomeController class has three dependencies: DB_11032022_LearnASPNETContext, IConfiguration, and IMemoryCache

DB_11032022_LearnASPNETContext is a database provider class injected as a dependency in the HomeController and later used throughout the Controller to manage database connectivity using Microsoft EntityFramework Core and LINQ. IConfiguration is an interface injected as a dependency in the HomeController and later used throughout the Controller. IMemoryCache is also an interface injected as a dependency in the HomeController and later used throughout the Controller. It represents a cache stored in the memory of the web server. These three objects do different things, yet we want our HomeController class to have access to the things they do. So, we inject these objects into the HomeController as parameters, as shown in the code example below. 

    public class HomeController : Controller
    {
        private readonly DB_11032022_LearnASPNETContext _context;
        private IConfiguration Configuration;
        private readonly IMemoryCache _memoryCache;

        public HomeController(DB_11032022_LearnASPNETContext context, IConfiguration configuration, IMemoryCache memoryCache)
        {
            _context = context;
            Configuration = configuration;
            _memoryCache = memoryCache;
        }

Later, in our action methods, we use the injected database provider class's "power" to query a Microsoft SQL Server database using LINQ.

results = await _context.ArticleSelect.FromSqlInterpolated($"exec dbo.ArticlesHomePage").ToListAsync();

The above approach is better than the following which always creates a new instance of a class. The following approach using the new keyword which tightly couples the HomeController class with the database provider class. That means the application will be challenging to change and maintain if we have instantiated the database provider class in multiple places using the new keyword. 

    public class HomeController : Controller
    {
        private readonly DB_11032022_LearnASPNETContext _context;
        private IConfiguration Configuration;
        private readonly IMemoryCache _memoryCache;
        
        public HomeController()
        {
            _context = new DB_11032022_LearnASPNETContext();
        }

What's interesting to note is that the DB_11032022_LearnASPNETContext class, which is a dependency of HomeController, also uses dependency injection to take advantage of Entity Framework's DbContext class, which represents a session with the database and can be used to query and save instances of your entities.

    public partial class DB_11032022_LearnASPNETContext : IdentityDbContext
    {
        public DB_11032022_LearnASPNETContext() { }
        public DB_11032022_LearnASPNETContext(DbContextOptions<DB_11032022_LearnASPNETContext> options)
            : base(options)
        {
        }
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
        }
        public virtual DbSet<ArticleSelect> ArticleSelect { get; set; } = null!;
        public virtual DbSet<TableArticles> TableArticles { get; set; } = null!;
        public virtual DbSet<TableAspnetVersions> TableAspnetVersions { get; set; } = null!;
        public virtual DbSet<TableCategories> TableCategories { get; set; } = null!;
        public virtual DbSet<TableExternalResources> TableExternalResources { get; set; } = null!;
        public virtual DbSet<TableInformationTypes> TableInformationTypes { get; set; } = null!;
        public DbSet<Images> Images { get; set; } = null!;
        public DbSet<Members> Members { get; set; }
        public DbSet<LearnASPNET.Models.PageContent> PageContent { get; set; }

    }

By default, dependency injection is inherent in ASP.NET core projects and is a great way to develop loosely coupled software components. Loose coupling means that if we change one object, that change will not impact other objects negatively. This independent object approach facilitates the management of future code changes in enterprise-level software applications.