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

Create the Update Page

In the last module we added the Create feature in order to let users add Vehicles to the database.

In this module we will add an Update feature so that users can update vehicle information.


A lot of the steps in creating the update/edit feature are going to be similar to the steps we took in developing the create feature in the last module.

The first thing we need to do is again extend the vehicles repo to include a method for updating a vehicle.

Table Of Contents
  1. Extend the Vehicles Repository
  2. Add the Edit action methods to the Vehicles controller
    • HttpGet Edit
    • HttpPost Edit
      • The TryUpdateModel pattern
      • Error Handling with the try/catch pattern
        • Exceptions

Extend the Vehicles Repository

Modify IVehicleRepository.cs with the code shown below.

FredsCars\Models\Repositories\IVehicleRepository.cs

namespace FredsCars.Models.Repositories
{
    public interface IVehicleRepository
    {
        IQueryable<Vehicle> Vehicles { get; }
        
        Task CreateAsync(Vehicle vehicle);
        Task UpdateAsync(Vehicle vehicle);
    }
}

Next modify EFVehicleRepository.cs with the code shown 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;

        public async Task CreateAsync(Vehicle vehicle)
        {
            await _context.Vehicles.AddAsync(vehicle);
            await _context.SaveChangesAsync();
        }

        public async Task UpdateAsync(Vehicle vehicle)
        {
            _context.Vehicles.Update(vehicle);
            await _context.SaveChangesAsync();
        }
    }
}

In this section we simply added a method definition to the Vehicle repo interface called UpdateAsync which takes in a Vehicle object and returns a Task and implemented it the EFVehicleRepository class much like we did for the Create feature in the last module. The implimentation uses the Vehicles DbSet’s Update method where the CreateAsync method used the Vehicles DbSet’s AddAsync method. A DbSet only has an Upddate method and no UpdateAsync method. But the change to the Entity’s state will be saved to the database asyncronously through the SaveChangesAsync method.

Add the Edit action methods to the Vehicles controller

HttpGet Edit

First let’s add the HttpGet Edit action method. Modify the Vehicles controller with the following code.

FredsCars\Controllers\VehiclesController.cs

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

namespace FredsCars.Controllers
{
    public class VehiclesController : Controller
    {
        private IVehicleRepository _vehicleRepo;
        private IVehicleTypeRepository _vehicleTypeRepo;

        public VehiclesController(IVehicleRepository vRepo,
            IVehicleTypeRepository vtRepo)
        {
            _vehicleRepo = vRepo;
            _vehicleTypeRepo = vtRepo;
        }

        ... existing code ...
    
        public async Task<ViewResult> Edit(int id)
        {
            Vehicle? vehicle = await _vehicleRepo.Vehicles
                .Include(v => v.VehicleType)
                .FirstOrDefaultAsync(v => v.Id == id);

            if (vehicle == null)
            {
                ViewBag.NoVehicleMessage =
               "Sorry, no vehicle with that id could be found.";
            }

            var vehicleTypes =
    _vehicleTypeRepo.VehicleTypes;

            ViewBag.VehicleTypeList = new SelectList(vehicleTypes,
    "Id", "Name");

            return View(vehicle);
        }
    }
}

In the code above for the GET Edit action method we start off by fetching a vehicle by its Id using a LINQ query very similar to the Details action method and assign the result to a variable named vehicle of Type Vehicle? (nullable Vehicle). Except here we do not include the AsNoTracking method of the Vehicles DbSet because we need EF Core to track the changes made to the entity update.

Vehicle? vehicle = await _vehicleRepo.Vehicles
    .Include(v => v.VehicleType)
    .FirstOrDefaultAsync(v => v.Id == id);

Next we also do a similar null check as in the Details action method and store the same “..no vehicle with that id…” message into a ViewBag dynamic property with the same name.

if (vehicle == null)
{
    ViewBag.NoVehicleMessage =
   "Sorry, no vehicle with that id could be found.";
}

If the vehicle object is not null, we borrow the next two code statements from the Create action method’s set up to create a SelectList object we will need for the Category select form control in the Edit view. To refresh our memory we use the VehicleTypes IQueryable property of the VehicleTypes repo as a parameter to the SelectList constructor, and pass “Id” and “Name” as the parameters for the dataValueField and dataTextField arguments for the drop down options in the View’s select form control.

var vehicleTypes =
    _vehicleTypeRepo.VehicleTypes;

ViewBag.VehicleTypeList = new SelectList(vehicleTypes,
    "Id", "Name");

As the last step we return a ViewResult with the vehicle to update as the model and only parameter of the View method.

return View(vehicle);

HttpPost Edit

Next let’s add the post edit action. Modify the Vehicles controller once more with the code shown below.

FredsCars\Controllers\VehiclesController.cs

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

namespace FredsCars.Controllers
{
    public class VehiclesController : Controller
    {
        ... existing code ...
    
        public async Task<ViewResult> Edit(int id)
        {
            Vehicle? vehicle = await _vehicleRepo.Vehicles
                .Include(v => v.VehicleType)
                .FirstOrDefaultAsync(v => v.Id == id);

            if (vehicle == null)
            {
                ViewBag.NoVehicleMessage =
               "Sorry, no vehicle with that id could be found.";
            }

            return View(vehicle);
        }
        
        [HttpPost]
	[ActionName("Edit")]
	[ValidateAntiForgeryToken]
	public async Task<IActionResult> EditPost(int id)
	{
		var vehicle = await _vehicleRepo.Vehicles
			.Include(v => v.VehicleType)
			.FirstOrDefaultAsync(v => v.Id == id);
		
		if (await TryUpdateModelAsync<Vehicle>(vehicle!,
				"",
				v => v.Status, v => v.Year, v => v.Make,
					v => v.Model, v => v.Color, v => v.Price,
					v => v.Price, v => v.VIN, v => v.ImagePath
		))
		{
			try
			{
				await _vehicleRepo.UpdateAsync(vehicle!);
				return RedirectToAction("Index", "Home");
			}
			catch (DbUpdateException ex)
			{
				// Log the exception
				//ex.Message, ex.Source, ex.StackTrace
					ModelState.AddModelError("",
						"There was a problem updating the vehicle."
						+ "Please contact your system administrator." );
			}
		}

                var vehicleTypes =
    _vehicleTypeRepo.VehicleTypes;

                ViewBag.VehicleTypeList = new SelectList(vehicleTypes,
    "Id", "Name");
		
		return View();
	}
    }
}

The new Post Edit action method takes in an id as the single parameter. If we named it Edit with the same parameter list as the Get Edit action, C# would complain that we have to methods with the same parameter types. C# does not allow this so we name the new action method EditPost. But when the user submits a post from the Get Edit action, ASP.Net core will be looking for a Post Edit action; not a Get EditPost method. To resolve this issue we decorate the action method with the ActionName attribute and tell it the real name of this method is Edit; not EditPost.

[HttpPost]
[ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int id)
{
   ...
}

Notice we also decorate the Post Edit action method with the HttpPost and ValidateAntiForgeryToken attributes to mark this method as the Post version of the Edit action and to Validate the CSRF token that will be sent up with the form post data from the form post of the Edit View just like in the Post Create action method.


The Edit method starts off again fetching the vehicle to update from the database using a LINQ query and assigning the result to a variable named vehicle.

The TryUpdateModel pattern

In the Post Create action method we used the Bind attribute with a list of Vehicle object properties that are allowed to be bound to form post fields to protect from OverPosting.

In the next part of the Post Edit method we use the TryUpdateModel pattern as an alternative way to defend against overposting in an Update/Edit method.

The setup part of the TryUpdateModel pattern here is to use the asynchronous version of the ControllerBase class’s generic TryUpdateModel method, TryUpdateModelAsync of type type Vehicle, along with the await keyword to force the method to actually perform asynchronously, in an if statement.

 if (await TryUpdateModelAsync<Vehicle>(vehicle!,
         "",
         v => v.Status, v => v.Year, v => v.Make,
         v => v.Model, v => v.Color, v => v.Price,
         v => v.Price, v => v.VIN, v => v.ImagePath
     ))
 {
   ...
}

The first parameter passed to TryUpdateModel[Async] is the Vehicle object to be updated; the same vehicle entity we just fetched with the LINQ statement.

The second parameter is a prefix that will be in front of form field names in the form post. It is set to blank, or no characters, with double quotes here ("") but this parameter will come in handy in the next chapter on Razor Pages.

A list of the object’s properties to update by model binding to matching fields in the form post comes at the end of the parameter list.

The TryUpdateMode[Async] method returns a boolean; true if the update succeeds and false if not.

Error Handling with the try/catch pattern

In the body of the if statement, if the model binding to update the object succeeds, we use the try/catch pattern to handle any exceptions that may occur.

The try/catch pattern looks like the following.

try
{
    // try to do something
}
catch(1stExpectedExceptionType ex)
{
    // handle the exception
}
catch(2ndExpectedExceptionType ex)
{
    // handle the exception
}
catch(Exception ex // the base exception class comes last)
{
    // handle the exception
}

In a try catch block of code we try to do something and if it fails we can have a multiple series of catch blocks to handle specific types of exceptions. The base exception comes last to handle the most generic type of exception.

In our try block of code we try to Update the Vehicle object with the Vehicle repo and redirect to the Home/Index action. But sometimes an error beyond our control can occur such as a bad network connection or a database being down.

try
{
    await _vehicleRepo.UpdateAsync(vehicle!);
    return RedirectToAction("Index", "Home");
}
Exceptions

If our catch block of code we check for a specific type of exception, DbUpdateException.

catch (DbUpdateException ex)
{
    // Log the exception
    //ex.Message, ex.Source, ex.StackTrace
    ModelState.AddModelError("",
        "There was a problem updating the vehicle."
        + "Please contact your system administrator." );
}

An exception is…

< 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
  • Create the Update 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