Skip to content
  • iImagine
  • Register
  • Log In

Web Development School

Learning made easy.

  • Books
    • Beginning Web Development with ASP.Net Core & Client-Side Technologies
      • TOC
      • Part 1
        • Chapter 1: Static HTML – Designing the landing page
      • Part 2
        • Chapter 2: ASP.Net Core – Let’s talk Dynamic
        • Chapter 3: Introduction to ASP.Net Core MVC
          [ASP.Net Core v9]
      • Part 4
        • Chapter 7: Using Server Side & Client Side technologies together
          [ASP.Net Core v7 & Angular 15]
  • Environment Setup
    • Installing Angular
    • Installing Visual Studio 2022
    • Installing SQL Server 2022 Express
    • Installing Postman
    • Installing Git for Windows
  • Blog
  • iImagine WebSolutions
  • Events
  • Learning Videos
  • Toggle search form

Repository Pattern: The Vehicles Repo

Table Of Contents
  1. The Repository Pattern
    • Create the Vehicle Repository
      • Create the Vehicle Repository Interface
      • Create the Vehicle Repository Implementation
    • Register the Vehicle Repository as a service
    • Inject the Repository into the Controller
  2. What's Next

In the last module we learned how to use the DI pattern. We used dependency injection to inject an instance of the FredsCarsDbContext service into the controller.

private FredsCarsDbContext _context;

public HomeController(FredsCarsDbContext context)
{
    _context = context;
}

This is better than manually instantiating the DbContext with the C# new keyword as shown in the following.

public HomeController()
{
    DbContextOptionsBuilder<FredsCarsDbContext> opts =
        new DbContextOptionsBuilder<FredsCarsDbContext>(
            // build options
    );
    var context = new FredsCarsDbContext(opts.Options);
}

But, we can still benefit from separating out the DbContext and data access by one more layer, further loosely coupling the DbContext service from the Controller component.

The Repository Pattern

We can do this with another popular pattern called called the repository pattern.

This pattern is widely used and can help us to reuse code and reduce code duplication. It can also provide a consistent way to access data through the DbContext. This is especially true with CRUD methods.

NOTE: CRUD stands for Create, Read, Update, and Delete, which are the four basic operations for managing data in a database.

Create the Vehicle Repository

Create the Vehicle Repository Interface

The first thing we need to do is create an Interface for the Vehicle Repository. Create a new folder called Repositories under the Models folder. Then create an interface called IVehicleRepository by right clicking on the new Repositories folder and selecting Add -> Class.

In the Add New Item dialogue, select Interface from the middle pane, name the file IVehicleRepository.cs, and click the Add button.

Modify IVehicleRepository.cs with the code shown below.

FredsCars\Models\Repositories\IVehicleRepository.cs

namespace FredsCars.Models.Repositories
{
    public interface IVehicleRepository
    {
        IQueryable<Vehicle> Vehicles { get; }
    }
}

In the code for the Interface above, we have declared a read only property called Vehicles that returns an IQueryable<T>, in our case an IQueryable<Vehicle>. The IQueryable<Vehicle> allows us to fetch a set of Vehicles in an abstract way.

Create the Vehicle Repository Implementation

The next thing we need to do is create an implementation of IVehicleInterface. Create a class in the Models\Repositories folder called EFVehicleRepository and modify it with the code below.

FredsCars\Models\Repositories\EFVehicleRepository.cs

using FredsCars.Data;

namespace FredsCars.Models.Repositories
{
    public class EFVehicleRepository : IVehicleRepository
    {
        private FredsCarsDbContext _context;

        public EFVehicleRepository(FredsCarsDbContext context)
        {
            _context = context;
        }

        public IQueryable<Vehicle> Vehicles => _context.Vehicles;
    }
}

In the code above, the first thing we do is perform DI and inject an instance of FredsCarsDbContext into the repository service.

private FredsCarsDbContext _context;

public EFVehicleRepository(FredsCarsDbContext context)
{
    _context = context;
}

Next, the EFVehicleRepository is implementing the IVehicleRepository interface. When you implement an interface, you have to implement every public property and method of the interface. Right now the IVehicleRepository interface only has one member, the Vehicles property. So we implement that property by returning the DbSet of Vehicles.

public IQueryable<Vehicle> Vehicles => _context.Vehicles;

In the code line above, we are not returning actual data records from the database but rather a DbSet. DbSet inherits from IQueryable. And IQueryable inherits from IEnumerable.

The IQueryable<T> interface inherits from IEnumerable<T> but it provides additional capabilities for querying data while still supporting basic enumeration.

We can build up queries using an IQueryable<T> in a method without hitting the database using LINQ methods such as Where and OrderBy.

public IQueryable<Vehicle> Vehicles 
    => _context.Vehicles
        .Where(v => v.VehicleType.Name == "Car")
        .OrderBy(v => v.Year);

Execution of IQueryable LINQ methods like Where and OrderBy are deferred. The SQL commands are not sent to the database until we either iterate through the DbSet with a foreach loop or call ToList() or ToListAsync() on the DbSet.

using FredsCars.Data;

namespace FredsCars.Models.Repositories
{
    public class EFVehicleRepository : IVehicleRepository
    {
        private FredsCarsDbContext _context;

        public EFVehicleRepository(FredsCarsDbContext context)
        {
            _context = context;
        }

        public IQueryable<Vehicle> Vehicles => _context.Vehicles;

        public List<Vehicle> SomeMethod()
        {
            List<Vehicle> results = new List<Vehicle>();
            // iteration gets data from database
            foreach (var vehicle in Vehicles)
            {
                if (vehicle.VehicleType.Name == "Car")
                {
                    results.Add(vehicle);
                }
            }
            return results;
        }
    }
}
public List<Vehicle> SomeMethod()
{
    // ToList() calls database and fetches data
    return _context.Vehicles.ToList();
}

Also note, the Vehicles property in the implementation is used to map the Vehicles property in the interface to the Vehicles DbSet property in the DbContext.

Register the Vehicle Repository as a service

The final thing we need to do is register the Vehicle Repository, or more accurately the IVehicle interface, as a service. Modify Program.cs with the code below.

FredsCars/Program.cs

using FredsCars.Data;
using FredsCars.Models;
using FredsCars.Models.Repositories;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add Services
builder.Services.AddControllersWithViews();

builder.Services.AddDbContext<FredsCarsDbContext>(opts =>
{
    opts.UseSqlServer(
        builder.Configuration["ConnectionStrings:FredsCarsMvcConnection"]
    );
});

builder.Services.AddScoped<IVehicleRepository, EFVehicleRepository>();

var app = builder.Build();

// Configure the HTTP request pipeline.
... existing code ...

Earlier in the chapter we talked about service lifetimes. In the code above we use the AddScoped method to add the IVehicleRepository service with a lifetime of scoped. This means a new IVehicleRepository instance will be created for each new request. And that same instance will be used as each component in the request lifetime does it’s job; from the middleware components chain on through to the controller.

builder.Services.AddScoped<IVehicleRepository, EFVehicleRepository>();

The AddScoped method takes two generic types; TService and TImplimentation.

AddScoped<TService, TImplementation>();

The TService type we are registering as the service is IVehicleRepository. The TImplimentation we are registering as the implementation class of the interface is EFVehicleRepository.


By setting up and registering a repository in this way, any component in the application that depends on the IVehicleRepository service doesn’t know or care about what class implements the service. It also doesn’t know the details of the implementation. This makes it easy to swap out another implementation class in the service registration in Program.cs without having to make any changes in the components that use the service, for instance, the controller.


Also notice we imported the FredsCars.Models.Repositories namespace into Program.cs with the using statement.

using FredsCars.Models.Repositories;

Inject the Repository into the Controller

Now that we have the repository ready to go, the last thing we need to do is inject it into the controller, replacing the FredsCarsDbContext service with the IVehicleRespository service. Modify the Home Controller with the modified code below.

FredsCars\Controllers\HomeController.cs

using FredsCars.Data;
using FredsCars.Models.Repositories;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace FredsCars.Controllers
{
    public class HomeController : Controller
    {
        private IVehicleRepository _repo;

        public HomeController(IVehicleRepository repo)
        {
            _repo = repo;
        }
        
        public async Task<ViewResult> Index()
        {
            return View(await _repo.Vehicles
                .Include(v => v.VehicleType)
                .ToListAsync());
        }
    }
}

In the code above, we still use dependency injection for the controller. But now we inject the vehicle repository containing the DbContext into the controller rather then the DbContext itself. To do this we change the type of the private field from FredsCarsDbContext to IVehicleRepository and the name from _context to _repo.

private IVehicleRepository _repo;

In the constructor we also change the type of the incoming constructor from FredsCarsDbContext to IVehicleRepository and rename it from context to repo. Then we assign the incoming repo service to the private field.

public HomeController(IVehicleRepository repo)
{
    _repo = repo;
}

Also, we no longer need the FredsCars.Data namespace but we did need to import the FredsCars.Models.Repositories namespace. This is because we are no longer accessing the FredsCarsDbContext class directly but rather through the repository.

If you restart and run the application the results should remain the same. But, now with the Vehicle Repository in place it is very easy to swap out different implementations for the IVehicleRepository service, or in other words, how the controller accesses and works with the database.

For instance, say we want to access the database using the ORM (Object Relational Mapper) called NHibernate rather than EF Core. We could just register a new implementation class for the IVehicleRepository service in Program.cs called NHVehicleRepository to replace EFVehcileRepository.

builder.Services.AddScoped<IVehicleRepository, NHVehicleRepository>();

Another benefit of being able to easily swap service implementations is during testing.

The repository layer loosely couples and isolates the controller from data access. If the controller was tightly coupled with the data access component, and we got an error during testing, we wouldn’t know if the error lied with the data access or in the controller itself.

In the next module we are going to create a Unit Test for the controller. In the Unit Test we will be able to create an implementation for the IVehicleRepository service explicitly for testing. To do this we will create a fake repository, or mock the IVehicleRepository with an implementation that returns exactly the data we specify instead of real data from the database. This way we know what data to expect and can test for that result.

So, during run time the Home controller will use the EFVehicleRepository implementation. And during testing it will use the mock implementation.

What’s Next

In this chapter we continued to build on the DI pattern and learned the Repository pattern while we created a repo for Vehicles.

In the next chapter we will create our first unit test for the home controller to make sure it can properly use the repository.

< Prev
Next >

Leave a ReplyCancel reply

Chapter 1: Static HTML – Designing the landing page.

  • Static HTML – Designing the landing page.
  • Let’s get started!
  • Mock your site with HTML
  • Make CSS easy with Bootstrap
  • Mock your content
  • Introducing JavaScript
  • JavaScript Code Improvements
  • Results Data
  • Images and the HTML Image Element.
  • Revisiting Reusability for CSS and JavaScript
  • Reuse for HTML: PART 1
  • Reuse for HTML: PART 2
  • Details Page – Using a Bootstrap Component
  • Creating Links
  • Chapter One Conclusion

Chapter 2: ASP.Net Core – Let’s talk Dynamic

  • Introduction to ASP.Net Core
  • What is .Net?
  • What is ASP.Net
  • Introduction to Entity Framework Core

Chapter 3: ASP.Net MVC Core – Models, Views, and Controllers [ASP.Net Core v9]

  • Introduction to ASP.Net Core MVC
  • Create the project: ASP.Net Core MVC
  • Explore the ASP.Net Core Empty Web Project Template
  • Configure the Application for MVC
  • Create a Controller: Home Controller
  • Create a View: Index View for the Home Controller
  • Install Bootstrap using Libman
  • Create the Layout template
  • Create the Model
  • Install EF Core & Create the Database
  • Seed the Database: Loading test data
  • DI (Dependency Injection): Display a List of Vehicles
  • Repository Pattern: The Vehicles Repo
  • Unit Test 1: Home Controller Can Use Vehicle Repository
  • Unit Test 2: Vehicle Repository Can Return List
  • Add the ImagePath Migration and Thumbnail images to results
  • Pagination: Create a Custom Tag Helper
  • Sorting
  • Category Filter
  • Partial View: Break out the vehicle results
  • View Component: Create dynamic category buttons
  • Create the Details page
  • Create the Create Page

Chapter 7: Using Server Side & Client Side technologies together. [ASP.Net Core v7 & Angular v15]

  • Intro to Full Stack Development
  • Fred’s Cars – Full Stack Development
  • Prepare the environment
  • Create the Visual Studio Solution
  • Add the ASP.Net Core Web API project
  • Add the Angular Project
  • Wire it up!
  • WeatherForecast: Understanding the basics
  • Vehicles API Controller: Mock Data
  • Vehicles Angular Component: Consuming Data
  • Routing and Navigation
  • Using a Component Library: Angular Material
  • Our first Angular Material Component: MatToolbar
  • Configuring for Saas: CSS with superpowers
  • Create the Header & Footer components
  • Displaying Results with MatTable
  • Loading: Using a Progress Spinner
  • MatTable: Client-Side Paging and Sorting
  • MatSidenav: Create a Search Sidebar
  • MatCheckbox: Category Search UI
  • Adding an image to the welcome page
  • Create the database with Entity Framework Core migrations
  • MatPaginator & PageEvent: Custom Server-Side Paging
  • Unit Testing: Custom Server-Side Paging
  • Repository Pattern: VehicleRepository
  • Unit Test: Paging in the Vehicles controller
  • Server-Side Sorting
  • Unit Tests: Sorting
  • Filter (Quick Search)
  • Unit Tests: Filter feature
  • Advanced Search: Categories
  • Unit Tests: Search by category
  • Progress Spinner: Final Fix

TOC

  • What were WebForms?
  • Enter MVC
    • Understanding MVC
    • Advantages of MVC
  • ASP.Net Core MVC – A total rewrite
  • ASP.Net Core 2 MVC – Here come Razor Pages
    • Understanding Razor Pages
  • ASP.Net Core 3 – Dropping the MVC reference
    • Understanding Blazor
  • Dropping the MVC reference
  • Hello .Net 5!
  • What’s Next? – Here comes .Net 6.

Recent Posts

  • Angular Commands Cheat Sheet
  • Installing Git for Windows
  • Installing Postman
  • Installing SQL Server 2022 Express
  • Installing Visual Studio 2022

Recent Comments

No comments to show.

Archives

  • November 2023
  • October 2023
  • June 2023
  • October 2021

Categories

  • Angular
  • ASP.Net
  • Environment Setup
  • See All
  • SQL Server
  • Visual Studio
  • Web API & Rest Services

WordPress Theme Editor

Copyright © 2025 Web Development School.

Powered by PressBook Blog WordPress theme