Showing posts with label Code 1st. Show all posts
Showing posts with label Code 1st. Show all posts

Wednesday, June 19, 2019

Build a Web API web app using Serverless Azure Functions with Entity Framework Migrations and Dependency Injection

One of the exciting developments from the Microsoft Build 2019 conference was support for dependency injection in Azure Functions. Combining Entity Framework Core and Dependency Injection with Azure Functions provides a very compelling opportunity to create data driven server-less solutions.

Source code for this tutorial can be found at: https://github.com/medhatelmasry/FunctionStudentsAPI

Let us create a very simple Azure Function that acts as a Web API endpoint.
Start Visual Studio 2019 and choose "Create a new project".

In the "Create a new project" dialog, select "Azure Functions" then click Next.

I named my project FunctionStudentsAPI. Give your project a name then click on Create.

Ensure that you have selected "Azure Functions V2 (.NET Core)" from the dropdown list at the top. Choose the "Http trigger" template and set Authorization level to Anonymous, then click on Create.

Let us see what the app does. Hit CTRL F5 on the keyboard. An output terminal window will launch that looks like this:

Copy and paste the URL into a browser.

The message in your browser suggests that you should pass a name query string. I appended the following to the URL: ?name=Superman. I got the following result:

We will need to add some Nuget packages. Execute the following dotnet commands from a terminal window:
dotnet add package Microsoft.Azure.Functions.Extensions   >> for Dependency Injection
dotnet add package Microsoft.EntityFrameworkCore   >> for Dependency Injection
dotnet add package Microsoft.EntityFrameworkCore.Design   >> for Entity Framework
dotnet add package Microsoft.EntityFrameworkCore.SqlServer  >> for Entity Framework Design Time Migration
dotnet add package Microsoft.EntityFrameworkCore.Tools   >> for Entity Framework Design Time Migration
dotnet add package Microsoft.Extensions.Http    >> for Http support
Let us make a few minor enhancements to our application.

1) Add a simple Student.cs class file to your project with the following content:
public class Student {
  public string StudentId { get; set; }
  [Required]
  public string FirstName { get; set; }
  [Required]
  public string LastName { get; set; }
  [Required]
  public string School { get; set; }
}

2) Change the C# class file name Function1.cs to FunctionStudents.cs.

3) Open FunctionStudents.cs in the editor and change the name of the class from Function1 to FunctionStudents.

4) Change the signature of the FunctionStudents class so that it does not have the static keyword. Therefore, the signature of the class will look like this:
public class FunctionStudents

5) Add an Entity Framework DbContext class. In our case, we will create a class file named SchoolDbContext.cs with the following content:
public class SchoolDbContext : DbContext {
    public DbSet<Student> Students { get; set; }

    public SchoolDbContext(DbContextOptions<SchoolDbContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder builder)     {
        base.OnModelCreating(builder);

        builder.Entity<Student>().HasData(
          new {
              StudentId = Guid.NewGuid().ToString(),
              FirstName = "Jane",
              LastName = "Smith",
              School = "Medicine"
          }, new {
              StudentId = Guid.NewGuid().ToString(),
              FirstName = "John",
              LastName = "Fisher",
              School = "Engineering"
          }, new {
              StudentId = Guid.NewGuid().ToString(),
              FirstName = "Pamela",
              LastName = "Baker",
              School = "Food Science"
          }, new {
              StudentId = Guid.NewGuid().ToString(),
              FirstName = "Peter",
              LastName = "Taylor",
              School = "Mining"
          }
        );
    }
}

6) To register a service like SchoolDbContext, create a class file named Startup.cs that implements FunctionStartup. This class will look like this:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;

[assembly: FunctionsStartup(typeof(FunctionStudentsAPI.Startup))]
namespace FunctionStudentsAPI {
  public class Startup : FunctionsStartup {
    public override void Configure(IFunctionsHostBuilder builder) {
      var connStr = Environment.GetEnvironmentVariable("CSTRING");
      builder.Services.AddDbContext<SchoolDbContext>(
        option => option.UseSqlServer(connStr));

      builder.Services.AddHttpClient();
    }
  }
}
7) Inject the objects that are needed by your function class. Open FunctionStudents.cs in the editor and add the following instance variables and constructor at the top of the class:
private readonly HttpClient _client;
private readonly SchoolDbContext _context;

public FunctionStudents(IHttpClientFactory httpClientFactory, 
  SchoolDbContext context) {
  _client = httpClientFactory.CreateClient();
  _context = context;
}
8) We want to use the design-time DbContext creation. Since we are not using ASP.NET directly here, but implementing the Azure Functions Configure method, Entity Framework will not automatically discover the desired DbContext. So we need to implement an IDesignTimeDbContextFactory to drive the tooling. Add a C# class file named SchoolContextFactory.cs and add to it the following content:
public class SchoolContextFactory : IDesignTimeDbContextFactory<SchoolDbContext> {
  public SchoolDbContext CreateDbContext(string[] args) {
    var optionsBuilder = new DbContextOptionsBuilder<SchoolDbContext>();
    optionsBuilder.UseSqlServer(Environment.GetEnvironmentVariable("CSTRING"));

    return new SchoolDbContext(optionsBuilder.Options);
  }
}
9) Entity Framework migrations expects the main .dll file to be in the root project directory. Therefore, we shall add a post-build event to copy the .dll file to the appropriate place. Add the following to the .csproj file:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
  <Exec Command="copy /Y &quot;$(TargetDir)bin\$(ProjectName).dll&quot; &quot;$(TargetDir)$(ProjectName).dll&quot;" />
</Target>

10) Go ahead and create a SQL Database Server in Azure. Copy the connection string into the following so that you can use it to set an environment variable in your computer's environment:
SET CSTRING=Server=tcp:XXXX.database.windows.net,1433;Initial Catalog=StudentsDB;Persist Security Info=False;User ID=YYYY;Password=ZZZZ;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

Where:  
XXXX is the name of your SQL Azure database server
YYYY is your database username
ZZZZ is your database password

Note: I called the database StudentsDB. You can call it whatever you like.

Open a terminal window at the root of your project and paste the environment variable. The syntax will differ if your do it in Linux or Mac.

Also, in Visual Studio, open launchSettings.json under the Properties node. Add the connection string as an environment variable so that the content looks like this:
{
  "profiles": {
    "FunctionStudentsAPI": {
      "commandName": "Project",
      "environmentVariables": {
        "CSTRING": "PUT THE CONECTION STRING HERE"
      }
    }
  }
}

11) The next step is to apply Entity Framework migrations. Execute the following command from the root of your project:
dotnet ef migrations add m1
This produces a Migrations folder in your project.
If you open the numbered file that ends in _m1.cs, it looks like this:
using Microsoft.EntityFrameworkCore.Migrations;

namespace FunctionStudentsAPI.Migrations {
  public partial class m1 : Migration {
    protected override void Up(MigrationBuilder migrationBuilder) {
      migrationBuilder.CreateTable(
        name: "Students",
        columns: table => new {
            StudentId = table.Column<string>(nullable: false),
            FirstName = table.Column<string>(nullable: false),
            LastName = table.Column<string>(nullable: false),
            School = table.Column<string>(nullable: false)
        }, constraints: table => {
            table.PrimaryKey("PK_Students", x => x.StudentId);
        });

      migrationBuilder.InsertData(
        table: "Students",
        columns: new[] { "StudentId", "FirstName", "LastName", "School" },
        values: new object[,] {
            { "695fef8f-6702-4a9c-a1f4-f49c798462c5", "Jane", "Smith", "Medicine" },
            { "b5e2814c-a56b-4bfc-a7cc-a1676763e43c", "John", "Fisher", "Engineering" },
            { "e80785c9-7a07-41a1-a932-c8c9a03e405a", "Pamela", "Baker", "Food Science" },
            { "215bcf8e-fd72-486d-842e-bb754c1d2ea5", "Peter", "Taylor", "Mining" }
        });
    }

    protected override void Down(MigrationBuilder migrationBuilder) {
      migrationBuilder.DropTable(
        name: "Students");
    }
  }
}

12) The next step is to create the database and tables. Execute the following command in the same terminal window as above:
dotnet ef database update
If all goes well, you will receive a message that looks like this:
Applying migration '20190620023500_m1'.
Done.
I went back in the Azure portal and found the database was created with the Students table:

13) Let us now create an endpoint in our Azure function that returns all the students as an API.

Add the following method to the Azure functions file named FunctionStudents.cs:
[FunctionName("GetStudents")]
public IActionResult GetStudents(
    [HttpTrigger(AuthorizationLevel.Function, "get", Route = "students")] HttpRequest req,
    ILogger log) 
{
    log.LogInformation("C# HTTP GET/posts trigger function processed a request.");

    var studentsArray = _context.Students.OrderBy(s => s.School).ToArray();

    return new OkObjectResult(studentsArray);
}

All that is left for us to do is test out our application and make sure it returns our students API. Run the application. You will see the following output in a terminal window:
Copy the second URL (I.E. http://localhost:7071/api/students) and paste it into a browser. The result will look like this:

Take Away

Creating an API with Azure Functions is much more cheaper than doing it with an ASP.NET Core Web application because you pay a fraction of a cent for every request and the app does not need to be constantly running. Also, it is very easy to do.

Friday, May 31, 2019

Blazor client-side app with CRUD operations against a Web API endpoint

A companion video for this article is: https://www.youtube.com/watch?v=wkSR3eo4Tek

Source code for this application can be found at:
https://github.com/medhatelmasry/BlazingSchool

Overview

What is Blazor?
Blazor is a framework for developing interactive client-side web applications using C# instead of JavaScript.

What are we going to do in this Tutorial?In this tutorial I will show you how to build a Blazor application with the following structure:
1) The class library will have model definitions that are shared between the Web API and Blazor Visual Studio projects. The model that we will create in this tutorial is a simple C# Student model that looks like this:

public class Student {
  public string StudentId { get; set; }
  [Required]
  public string FirstName { get; set; }
  [Required]
  public string LastName { get; set; }
  [Required]
  public string School { get; set; }
}

2) The ASP.NET Core Web API app will provide the REST endpoints for the students service that the Blazor client-side application will consume. It will use the GET, POST, PUT and DELETE methods to carry out CRUD operations with the API service. Entity Framework will be used to save data in SQL Server using the "Code First" approach.

3) The Client-side Blazor app will provide the user interface for processing student data.

Perquisites

This tutorial was written while Blazor was in preview mode. I used the following site for setting up my environment:

This is how I setup my development environment:

- .NET Core 3.0 Preview SDK installed from https://dotnet.microsoft.com/download/dotnet-core/3.0

- Install Blazor templates by running the following command in a terminal window:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.0.0-preview5-19227-01

- Visual Studio 2019 preview version installed from: https://visualstudio.com/preview

- Latest Blazor extension for Visual Studio 2019 installed from https://go.microsoft.com/fwlink/?linkid=870389.

Creating the class library

Create a new project in Visual Studio 2019.

Choose "Class Library (.NET Standard)" then click Next:

Set these values on the next dialog:

Project name: SchoolLibrary
Solution name: School

Click on Create.

We need to install a package to the class library project. From within a terminal window at the main SchoolLibrary folder, run the following command:

dotnet add package System.ComponentModel.Annotations

Delete Class1.cs, then create a new Student.cs class file and add to it the following code:
public class Student {
  public string StudentId { get; set; }
  [Required]
  public string FirstName { get; set; }
  [Required]
  public string LastName { get; set; }
  [Required]
  public string School { get; set; }
}

Resolve "Required" by adding the following using statement at the top of Student.cs:
using System.ComponentModel.DataAnnotations;

Creating the ASP.NET Core Web API student service application

Right-click on the main solution node in Solution Explorer and select: Add >> New Project. Choose the "ASP.NET Core Web Application" template:
Name the Project name: SchoolAPI

Click on Create.

On the next dialog, select ASP.NET Core 2.2 and choose the API template then click on Create:

Our Web API project needs to use the Student class in the SchoolLibrary project. Therefore, we will make a reference from the SchoolAPI project to the SchoolLibrary project. Right-click on the SchoolAPI project node then: Add >> Reference... >> Projects >> Solution >> check SchoolLibrary. Then click on OK.


We need to let the dotnet utility know that we are using .NET Core 2.2 in the SchoolAPI project, even though the default SDK on our computer is a preview version of .NET Core 3.0. This is done by adding a global.json file in the root SchoolAPI folder with the following content:
{
  "sdk": {
    "version": "2.2.103"
  }
}

A quick way of doing this is to run the following CLI command inside the SchoolAPI folder:
dotnet new globaljson --sdk-version 2.2.103

Since we will be using SQL Server, we will need to add the appropriate Entity Framework packages and tooling. From within a terminal window at the root of your StudentAPI project,  run the following commands that will import the appropriate database related packages:
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.SqlServer.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools

We need to add a connection string to the database. Add the following to the top of the appsettings.json file in project SchoolAPI:
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=SchoolDB;Trusted_Connection=True;MultipleActiveResultSets=true"
  },

We will be using the Entity Framework Code First approach. The starting point is to create a database context class. Add a C#  class file named SchoolDbContext.cs with the following class code:
public class SchoolDbContext : DbContext {
  public DbSet<Student> Students { get; set; }

  public SchoolDbContext(DbContextOptions<SchoolDbContext> options) : base(options) { }

  protected override void OnModelCreating(ModelBuilder builder) {
    base.OnModelCreating(builder);
    
    builder.Entity<Student>().HasData(
      new { StudentId = Guid.NewGuid().ToString(), 
            FirstName = "Jane", LastName = "Smith", School = "Medicine" },
      new { StudentId = Guid.NewGuid().ToString(), 
            FirstName = "John", LastName = "Fisher", School = "Engineering" },
      new { StudentId = Guid.NewGuid().ToString(), 
            FirstName = "Pamela", LastName = "Baker", School = "Food Science" },
      new { StudentId = Guid.NewGuid().ToString(), 
            FirstName = "Peter", LastName = "Taylor", School = "Mining" }
    );
  }
}

You will need to resolve some of the unrecognized namespaces.

Notice the above code is adding four records of seed data into the database.

In the Startup.cs file in the SchoolAPI project, add the following code to the ConfigureServices() method so that our application can use SQL Server:

services.AddDbContext<SchoolDbContext>(
  option => option.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
We are now ready to apply Entity Framework migrations, create the database and seed data. Remember to build your entire solution before proceeding. Then, from within a terminal window in the SchoolAPI directory, run the following command to create migrations:
dotnet ef migrations add initial_migration

This results in the creation of a migration file ending with the name ....initial_migration.cs in the Migrations folder. In my case, this file looked like this:
using Microsoft.EntityFrameworkCore.Migrations;
namespace SchoolAPI.Migrations {
  public partial class initial_migration : Migration {
    protected override void Up(MigrationBuilder migrationBuilder) {
      migrationBuilder.CreateTable(
        name: "Students",
        columns: table => new {
          StudentId = table.Column<string>(nullable: false),
          FirstName = table.Column<string>(nullable: false),
          LastName = table.Column<string>(nullable: false),
          School = table.Column<string>(nullable: false)
        },
        constraints: table => {
          table.PrimaryKey("PK_Students", x => x.StudentId);
        });

      migrationBuilder.InsertData(
        table: "Students",
        columns: new[] { "StudentId", "FirstName", "LastName", "School" },
        values: new object[,] {
          { "8734ce0b-4337-487a-bd86-102130d47f8d", "Jane", 
            "Smith", "Medicine" },
          { "db356c3a-d745-4f65-9aac-234f706859c2", "John", 
            "Fisher", "Engineering" },
          { "7721c620-a82b-4204-80af-6c7636efc81e", "Pamela", 
            "Baker", "Food Science" },
          { "9a85f51f-160e-4003-9de9-b01354e180a3", "Peter", 
            "Taylor", "Mining" }
        });
    }

    protected override void Down(MigrationBuilder migrationBuilder) {
      migrationBuilder.DropTable(
        name: "Students");
    }
  }
}

Note that the above code also includes commands for inserting sample data.

The next step is to create the SchoolDB database in SQL Server. This is done by running the following command from inside a terminal window at the SchoolAPI folder.

                                dotnet ef database update


If no errors are encountered, we can assume that the database was created and properly seeded with data. Let us create an API controller so that we can see the data that is in our database.  

Right-click on the Controllers node in the SchoolAPI project then: Add >> Controller...

Under Installed >> Common, choose the API tab, highlight "API Controller with actions, using Entity Framework" then click Add.



On the next dialog, make the following choices:

Model class: Student (SchoolLibrary)
Data context class: SchoolDbContext (SchoolAPI)
Controller name: StudentsController


Once you click on Add, the StudentsController.cs file is created in the Controllers folder. To load that particular controller every time you run the SchoolAPI application, edit the launchSettings.json file under the Properties node. Change every instance of "api/values" to "api/students". Now you can run the application by hitting CTRL F5 on your keyboard. This is what you should see in your browser:

[{"studentId":"7721c620-a82b-4204-80af-6c7636efc81e",
  "firstName":"Pamela","lastName":"Baker","school":"Food Science"},
{"studentId":"8734ce0b-4337-487a-bd86-102130d47f8d",
  "firstName":"Jane","lastName":"Smith","school":"Medicine"},
{"studentId":"9a85f51f-160e-4003-9de9-b01354e180a3",
  "firstName":"Peter","lastName":"Taylor","school":"Mining"},
{"studentId":"db356c3a-d745-4f65-9aac-234f706859c2",
  "firstName":"John","lastName":"Fisher","school":"Engineering"}]

Even though our API app seems to be working fine, there is one more thing we need to do. We need to enable CORS (Cross Origin Resource Sharing) so that the service can be accessed from other domains. Add the following code to the ConfigureServices() method in the Startup.cs file found in the SchoolAPI project:

// Add Cors
services.AddCors(o => o.AddPolicy("Policy", builder => {
  builder.AllowAnyOrigin()
    .AllowAnyMethod()
    .AllowAnyHeader();
}));

Add this statement in the Configure() method also in Startup.cs just before app.UseMvc():

            app.UseCors("Policy");

We now have an API and data that we can work with. Let us now see how we can use this data in a Blazor app.

Creating our Client-Side Blazor app

Let us add a client-side Blazor project to our solution. In Solution Explorer, right-click on the Solution node then: Add >> New Project...

Choose the "ASP.NET Core Web Application" template then click on Next.


Name the project SchoolClient, then click on Create.

Choose "ASP.NET Core 3.0" and the "Blazor (client-side)" template then click on Create.

Let us run our Blazor application to see what we have out of the box. Run the SchoolClient application by hitting CTRL F5 on your keyboard. You will see a UI that looks like this:

We will add a Students razor page and menu item to this client-side Blazor application.

Our Blazor project needs to use the Student class in the class library. Therefore, we will make a reference from the Blazor SchoolClient project to the class library project SchoolLibrary. Right-click on the SchoolClient project node then: Add >> Reference... >> Projects >> Solution >> check SchoolLibrary. Then click OK.


Open the _Imports.razor file in the editor and add the following using statement to the bottom of the content so that the Student class is available to a  views:

@using SchoolLibrary

Make a duplicate copy of the FetchData.razor file in the Pages node and call the new file Students.razor. Replace its contents with the following code:

@page "/students"
@inject HttpClient httpClient

<h1>Students</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (students == null) {
<p><em>Loading...</em></p>
} else {
<table class='table table-hover'>
  <thead>
    <tr>
      <th>ID</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>School</th>
    </tr>
  </thead>
  <tbody>
    @foreach (var item in students) {
    <tr>
      <td>@item.StudentId</td>
      <td>@item.FirstName</td>
      <td>@item.LastName</td>
      <td>@item.School</td>
    </tr>
    }
  </tbody>
</table>
}

@functions {
  Student[] students;
  string baseUrl = "https://localhost:44318/";

  protected override async Task OnInitAsync() {
    await load();
  }

  protected async Task load() {
    students = await httpClient.GetJsonAsync<Student[]>($"{baseUrl}api/students");
  }
}

NOTE: Make sure you adjust the value of baseUrl to match the URL of your SchoolAPI service.

Let us focus on the @functions block. The OnInitAsyns() method is called when the page gets loaded. It calls a local load() method. The load() method loads a students array with data from our SchoolAPI service. The remaining HTML/Razor code simply displays the data in a table.

Let us add a menu item to the left-side navigation of our client application. Open Shared/NavMenu.razor in the editor and add the following <li> to the <ul> block (around line 24):

<li class="nav-item px-3">
  <NavLink class="nav-link" href="students">
    <span class="oi oi-list-rich" aria-hidden="true"></span> Students
  </NavLink>
</li>

You must be looking forward to testing our client-side application. To run your app, highlight the SchoolAPI node then hit CTRL F5 to run the server-side application without debugging. This starts the API service.

Next, we will run the client-side Blazor application. Highlight the SchoolClient node then hit CTRL F5 to run the blazor app. This is what it should look like when you click on Students:


Adding data using the POST method
The client side application will not be complete without adding to it add, edit and delete funtionality. We shall start with adding data. Place the following instance variables just above the OnInitAsyc() method:

string studentId;
string firstName;
string lastName;
string school;

We need an HTML form to add data. Add the following RAZOR code just before @functions:

@if (students != null) // Insert form
{
  <input placeholder="First Name" bind="@firstName" /><br />
  <input placeholder="Last Name" bind="@lastName" /><br />
  <input placeholder="School" bind="@school" /><br />
  <button onclick="@Insert" class="btn btn-warning">Insert</button>
}

When the Insert button is clicked, an Insert() method is called. Add the following Insert() method inside the @functions() block that makes a POST request to the API service:
protected async Task Insert() {
  string endpoint = $"{baseUrl}api/students";

  Student student = new Student() {
    StudentId = Guid.NewGuid().ToString(),
    FirstName = firstName,
    LastName = lastName,
    School = school
  };

  await httpClient.SendJsonAsync(HttpMethod.Post, endpoint, student);
  ClearFields();
  await load();
  StateHasChanged(); // causes the page to get automatically refreshed
}

After data is added, the above code clears the fields then loads the data again in the HTML table. Add the following ClearFields() method:

protected void ClearFields() {
  studentId = string.Empty;
  firstName = string.Empty;
  lastName = string.Empty;
  school = string.Empty;
}

Run the Blazor client-side application and select Students from the navigation menu. This is what it should look like:



I entered David, Strong and Entertainment for data and when I clicked on Insert I got the following data added to the database:
Updating & Deleting data using the PUT & DELETE methods
To distinguish between INSERT and EDIT/DELETE mode, we shall add an enum to our code. Add the following to the list of instance variables:

private enum MODE { None, Add, EditDelete };
MODE mode = MODE.None;
Student student;

We will add a button at the top of our table dedicated to adding data. Add the following markup just above the opening <table> tag:

<button onclick="@Add"  class="btn btn-success">Add</button>

Let us add the following Add() method:

protected void Add() {
  ClearFields();
  mode = MODE.Add;
}

Around line 34, change the @if (students != null) statement to:

@if (students != null && mode==MODE.Add)

If you run the application, the form for inserting data only displays when the Add button is clicked:
After we successfully insert data, we want the insert form to disappear. Add the following code to the bottom of the Insert() method:
mode = MODE.None;
Let us now add a form that only appears when we wish to update or delete data. Add the following just before @functions:

@if (students != null && mode==MODE.EditDelete) // Update & Delete form
{
  <input type="hidden" bind="@studentId" /><br />
  <input placeholder="First Name" bind="@firstName" /><br />
  <input placeholder="Last Name" bind="@lastName" /><br />
  <input placeholder="School" bind="@school" /><br />
  <button onclick="@Update" class="btn btn-primary">Update</button>
  <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>
  <button onclick="@Delete" class="btn btn-danger">Delete</button>
}

Add these Update() and Delete() methods as shown below:

protected async Task Update() {
  string endpoint = $"{baseUrl}api/students/{studentId}";

  Student student = new Student() {
    StudentId = studentId,
    FirstName = firstName,
    LastName = lastName,
    School = school
  };

  await httpClient.SendJsonAsync(HttpMethod.Put, endpoint, student);
  ClearFields();
  await load();
  mode = MODE.None;
  StateHasChanged(); // causes the page to get automatically refreshed
}

protected async Task Delete() {
  string endpoint = $"{baseUrl}api/students/{studentId}";
  await httpClient.SendJsonAsync(HttpMethod.Delete, endpoint, null);
  ClearFields();
  await load();
  mode = MODE.None;
  StateHasChanged(); // causes the page to get automatically refreshed
}

We want to be able to select a row of data and update it. We can add an onclick handler to a row. In the HTML table, replace the <tr> opening tag under the @foreach statement with this:

<tr onclick="@(() => Show(item.StudentId))">

The above would pass the appropriate studentId to a method named Show() whenever a row is clicked. Add the following Show() method that retrieves a student from the API service and displays it in the Update/Delete form:

protected async Task Show(string id) {
  student = await httpClient.GetJsonAsync<Student>($"{baseUrl}api/students/{id}");
  studentId = student.StudentId;
  firstName = student.FirstName;
  lastName = student.LastName;
  school = student.School;
  mode = MODE.EditDelete;
}

Let us run the application and test it out for adding, updating and deleting data. Run the application:
Click on the Add button to insert data. 
Enter data then click on the Insert button. The data should get added to the database:

To update the data, click on a row. The selected data should display in the update/delete form.

I selected Bill Black and changed Black to White then clicked on Update. Last Name was successfully changed to White.

Lastly, let us delete a record. I clicked on the Bill White row. Data was displayed in the Update/Delete form.
When I clicked on Delete, Bill White get deleted.
I hope you found this tutorial useful. I expect Blazor to change by the time it is generally available in release mode. I will do my best to update this article with any breaking changes.