LogoLogo
  • FAC Curriculum
  • archive
    • Node & npm introduction
    • developer
      • Programming Paradigms
    • handbook
      • Asking for help
      • Coaching groups
      • Code review
      • Course rules
      • Debugging
      • Employment schedule and material delivered in FAC20
      • GitHub Workflow
      • Glossary or terms
      • Presentation Guidance
      • Equality, Diversity and Inclusion
      • Installation guide
      • Learning circles
      • Mentoring guidance
      • What to expect from your mentors
      • One-day projects
      • Pair programming
      • Portfolio
      • Questions for problem solving
      • Progress Logs
      • Final project report
      • Managing software projects
      • Project Presentations
      • Project roles
      • Projects
      • Retrospectives
      • Role Circles
      • Safeguarding policy
      • Technical Spikes
      • System requirements
      • Tech for Better
      • User Manuals
      • Wellbeing Support
      • project-docs
        • What makes a mentor?
        • Product Handover
        • Sprint Planning
        • Tech for Better Presentations
        • User Research & Usability Testing
    • foundation
      • full-stack
        • Learning Outcomes
        • project
      • testing
        • project
        • spikes
  • docs
    • Contributing to the curriculum
    • Curriculum intent
    • Curriculum process
  • src
    • About our curriculum
    • course
      • Code of Conduct
      • Docker
      • .NET and Umbraco
      • Getting started
      • Founders and Coders coursebook
      • KSB's
      • Mini projects
      • Revision checklist
      • Svelte
      • TypeScript
      • handbook
        • Software Developer Handbook
        • Software Foundation Handbook
      • precourse
        • Before you start the course
        • Installation List
      • syllabus
        • developer
          • app
            • learning-outcomes
            • project
            • schedule
            • spikes
          • introduction
            • learning-outcomes
            • project
            • resources
            • schedule
          • week00-pre-course
            • We'd like you to spend some time before starting the course working on useful fundamentals.
            • spikes
          • week01-project01-basics
            • Employability introduction
            • Homework
            • learning-outcomes
            • Week of September 9th
            • project
            • resources
            • schedule
            • spikes
          • week02-project02-chatbot
            • employability
            • Homework
            • learning-outcomes
            • Week of September 16th
            • project
            • resources
            • schedule
            • spikes
          • week03-project03-server
            • Learning Outcomes
            • Week of September 23th
            • The Amazin' Quizzer API Backend
            • resources
            • schedule
          • week04-project03-frontend
            • learning-outcomes
            • Week of September 30th
            • UI for Quizzer App
            • resources
            • schedule
          • week05-project03-test-deploy
            • Testing and deployment
            • Week of October 7th
            • project
            • resources
            • schedule
          • week06-project04-databases
            • learning-outcomes
            • Week of October 14th
            • project
            • Databases
            • schedule
          • week07-project04-authentication
            • Learning Outcomes
            • Week of October 21st
            • project
            • resources
            • schedule
          • week08-project04-test-deploy
            • Learning Outcomes
            • Week of October 28th
            • project
            • resources
            • schedule
          • week09-reading-week
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
          • week10-project05-DOTNET-intro
            • Learning Outcomes
            • overview
            • project
            • Resources
            • schedule
          • week11-project05-DOTNET-testing
            • Testing and deployment
            • Week of November 18th
            • project
            • Resources
            • schedule
          • week12-project05-DOTNET-deploy
            • Learning Outcomes
            • Week of November 25th
            • project
            • Resources
            • schedule
            • Spikes
          • week13-TFB-design
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Design Week Spikes
          • week14-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • DevOps Resources
            • schedule
            • Spikes
          • week15-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Spikes
          • projects
            • in-house-design
              • Learning Outcomes
              • Project
              • Resources
              • schedule
              • Design Week Spikes
        • foundation
          • Obsolete-full-stack
            • project
          • post-course
            • Homework
            • schedule
        • portfolio
          • fruit-shop
            • learning-outcomes
            • project
            • resources
          • game
            • learning-outcomes
            • project
            • resources
          • hobby-page
            • learning-outcomes
            • project
            • resources
          • movie-data
            • learning-outcomes
            • project
            • resources
          • project-gallery
            • learning-outcomes
            • project
            • resources
          • website
            • learning-outcomes
            • project
            • JavaScript
        • tfb
          • week 1
            • Introduction (45 minutes)
            • Further reading
          • week 10
            • content
            • resources
          • week 11
            • What will we be doing this week?
            • resources
          • week 12
            • What will we be doing this week?
            • Further reading
          • week 2
            • Discover (90 minutes)
            • resources
          • week 3
            • content
            • resources
          • week 4
            • Mapping the user journey (90 minutes)
            • resources
          • week 5
            • Figma Workshop 1 (90 minutes)
            • Further reading
          • week 6
            • Figma Workshop 2 (90 minutes)
            • resources
          • week 7
            • Product pitches & Selection (90 minutes)
            • resources
          • week 8
            • content
            • resources
          • week 9
            • content
            • resources
    • learn
      • DOTNET
        • Introduction to .NET
      • auth
        • Authenticating web apps
      • database
        • Persisting data with SQLite and Node
      • dotnet-two
        • Dependency injections and interfaces in .NET
      • form-validation
        • Form validation
      • react
        • Building client-side apps with React
      • server
        • HTTP servers with Node & Express
      • typescript
        • TypeScript
    • mentoring
      • design-week
        • Analysis Workshop
        • Code planning
        • Definition Workshop
        • Discovery Workshop
        • Figma introduction
        • Usability testing
        • User Research
    • resources
      • http
        • introduction
    • workshops
      • cookie-auth
        • index
      • creating-promises
        • index
      • css-layout
        • index
      • cypress-testing
        • index
      • database-testing
        • index
      • dev-tooling
        • Developer tooling
      • dom-challenge
        • index
      • dom-rendering
        • index
      • es-modules
        • index
      • express-middleware
        • Express middleware
      • first-class-functions
        • index
      • form-validation
        • index
      • functions-callbacks-async
        • Functions, callbacks, & async JavaScript
      • git-intro
        • Introduction to Git
      • git-terminal
        • Using Git in the terminal
      • git-workflow
        • Git workflow
      • github-projects
        • GitHub Projects Workflow Workshop
      • heroku-sql-challenge
        • index
      • html-forms
        • index
      • learn-a11y
        • index
        • starter-files
          • solution
            • Accessibility solution explanation
      • learn-fetch
        • index
      • learn-integration-testing
        • index
      • learn-testing
        • Learn testing in JavaScript
      • learn-unit-testing
        • index
      • node-error-handling
        • Node error-handling
      • node-express-server
        • Node and Express HTTP server
      • node-npm-intro
        • Node & npm introduction
      • node-postgres
        • Learn Postgres with Node
      • node-scripting-challenge
        • index
      • password-security
        • index
      • promise-practice
        • index
      • react-components
        • React components
      • react-fetch
        • index
      • react-forms
        • React forms
      • react-refactor-classes
        • index
      • react-state-effects
        • React state & effects
      • real-world-fetch
        • index
      • scope-challenge
        • Scope debugging challenge
      • semantic-html
        • index
      • server-side-forms
        • Server-side forms
      • session-auth
        • Session authentication
      • sql-intro
        • index
      • tdd-array-methods
        • index
Powered by GitBook
On this page
  • Why Dependency Injections
  • Set up
Export as PDF
  1. src
  2. learn
  3. dotnet-two

Dependency injections and interfaces in .NET

Learn how to use dependency injections and interfaces in .NET

Why Dependency Injections

It is quite common to have an object that depends on another object to do its function, especially in an object-oriented environment like .NET. For instance, your constructor depends on your data context object. However, it can cause problems to always have to build dependencies first and then the objects that depend on them next. Also what if two classes need to access different versions of the dependency for example we might want to use the data context class both in a testing class and in the actual project but when using it in the testing context, we might want to set it up in such a way that we don't actually affect the database we could do this by adjusting the controller class but it would be easier if we could make that class initially more flexible.

The solution to these problems is dependency injections where rather than creating a dependency that a class depends on we give the class an interface to tell it what type of object to expect and then create a service that allows us to create dependencies as needed and inject them into the class.

Set up

Open the simple hello world project you made last week. Within MyWebApi (or whatever you named the project) add a models directory and create a Book.cs file within it that looks like this

namespace MyWebApi.Models
{


    public class Book
    {
        public Guid Id {set; get;}
        public string? Name {set; get;}
       


    }
}

We now need to install Microsoft EntityFrameworkCore to help set up a quick in-memory database. Like so



dotnet add package Microsoft.EntityFrameworkCore

Then we make a data folder and inside make a BookContext.cs file that will look like so

using Microsoft.EntityFrameworkCore;
using MyWebApi.Models;
namespace  MyWebApi.Data
{
    public class BookContext : DbContext
    {
        public BookContext(DbContextOptions options): base(options){}
       
        public  DbSet<Book> Books {set; get;}
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
modelBuilder.Entity<Book>().HasData(
new Book {Id = Guid.NewGuid(), Name = "The Prospects"},
new Book {Id = Guid.NewGuid(), Name = "Nevada"}






);


            base.OnModelCreating(modelBuilder);
        }


    }


}

This is moving towards a simple in-memory database containing two books with randomly generated IDs. First, we will need to update our Program.cs file to use them.

Start by installing the following package

dotnet add package Microsoft.EntityFrameworkCore.InMemory

Then update the Program.cs file to look like what follows.

 using Microsoft.EntityFrameworkCore;
using MyWebApi.Data;


var builder = WebApplication.CreateBuilder(args);


// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<BookContext>(options => options.UseInMemoryDatabase("book db"));
builder.Services.AddControllers();


var app = builder.Build();
using(var scope = app.Services.CreateScope())
using(var db = scope.ServiceProvider.GetService<BookContext>()!)
{
    db.Database.EnsureCreated();
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}


app.MapControllerRoute("default", "api/[controller]/[action]");




app.UseHttpsRedirection();








app.Run();



This should give our BookContext the power to create in-memory databases and ensure they are created on app build.

Now let's update our controller to be a book controller that returns a list of books.

using Microsoft.AspNetCore.Mvc;
using MyWebApi.Data;
using MyWebApi.Models;




namespace MyWebApi.Controllers
{
      [ApiController]
    [Route("api/[controller]/[action]")]
public class BookController : Controller
{
    private readonly BookContext _context;
    public  BookController(BookContext context)
    {
        _context = context;
    }
    [HttpGet]
    public List<Book> GetAllBooks()
    {
        var result = _context.Books.ToList();
        return result;
    }


    [HttpGet]
    public Book GetABook(string name)
    {
var result = _context.Books.FirstOrDefault<Book>((book)=> book.Name== name);


            if (result == null)
                throw new Exception("book not found");
return result;
    }
}
}

Give it a quick swagger test, and then let's look at a part of this code in more detail.

public class BookController : Controller
{
    private readonly BookContext _context;
    public  BookController(BookContext context)
    {
        _context = context;
    }

The constructor for this class (line 4) requires BookContext to function. This means these two objects are now tightly linked and we can't easily change one without changing the other.

To allow us more flexibility we are going to create something called an interface that we can feed in instead. An interface lets the constructor know what to expect but will not be as absolute as actually giving it the class.

The first step to do that is to go into our data directory and make a new file called IBookContext that looks like this.

using MyWebApi.Models;
using Microsoft.EntityFrameworkCore;


namespace MyWebApi.Data
{
     public interface IBookContext
    {
public DbSet<Book> Books {set; get;}    
}
}

This creates an interface and tells the class passed this that at run time it can expect something that contains a DbSet of books rather than the specific class passed to it before. Now we just need to tell all the other parts of our program to look for the interface rather than the object.

Let's start with the BookContext file itself.

using Microsoft.EntityFrameworkCore;
using MyWebApi.Models;
namespace  MyWebApi.Data
{
    public class BookContext : DbContext ,IBookContext
 

If we make this change the BookContext can now inherit from both DbContext and IBookContext.

Now we want to update our Program.cs file so that when the context is built it knows it can take anything that matches the interface requirements

builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<IBookContext,BookContext>(options => options.UseInMemoryDatabase("book db"));
builder.Services.AddControllers();

Finally, we do what we wanted to all along which is to make our book controller independent from the BookContext class by putting our interface in the constructor.



public class BookController : Controller
{
    private readonly IBookContext _context;
    public  BookController(IBookContext context)

Besides making your work easier by having these two things looser it will also give you the ability to if you created an xUnit testing environment (like the one in the challenge repo), write code like this that substitutes fake data for the book context.



 {
    public class BookControllerTests
    {


        private readonly BookController _controller;
        public  BookControllerTests()
        {


var fakeData = new List<Book>
{
    new Book {Id = Guid.NewGuid(), Name = "Fake book1" },
        new Book {Id = Guid.NewGuid(), Name = "Fake book2" }




}.AsQueryable();        
var _context = new Mock<IBookContext>();  
_context.Setup(db => db.Books).ReturnsDbSet(fakeData);


_controller = new BookController(_context.Object);
        }


[Fact]        
public void GetAllBooks_Returns_Entire_List()
{


    var expected = new List<Book>
{
    new Book {Id = Guid.NewGuid(), Name = "Fake book1" },
        new Book {Id = Guid.NewGuid(), Name = "Fake book2" }




}.AsQueryable();


var result = _controller.GetAllBooks().ToList();


Assert.Equivalent(expected, result);
}


[Fact]
public void GetABook_Returns_A_Book()
{
    var expected =     new Book {Id = Guid.NewGuid(), Name = "Fake book1" };








var result = _controller.GetABook("Fake book1");


Assert.Equivalent(expected, result);


    }
}
}

Note this part which would not be possible if the Book controller relied on a BookContext

var _context = new Mock<IBookContext>();  
_context.Setup(db => db.Books).ReturnsDbSet(fakeData);


_controller = new BookController(_context.Object);
Previousdotnet-twoNextform-validation

Last updated 10 months ago