Asp Net Single Page Application Tutorial

These days, it is a common trend to build a single page application (SPA) using a modern front-end web framework such as Angular, React, Vue, etc., and a server-side backend Web API. In this tutorial, I will walk you through a complete example of creating a single page application using Angular that will connect a peladen-side ASP.NET Core 5 Web API to fetch data from a SQL Server database using Entity Framework Core (Code First). At the end of this tutorial, you will be able to display some useful stats related to football players.


What is a Single Page Application (SPA)

A single page application (SPA) is a type of web application that doesn’t load entire new pages from the server in an old and traditional way but instead loads data and contents from the server dynamically. SPA loads all necessary HTML, JavaScript, and CSS with a single page load, and the remaining resources are loaded dynamically usually from a backend Web API, and added to the page on different user actions. This technique results in an improved user experience because the user stays on the same page and control is never transferred to another page. Some popular examples of SPAs are Gmail, Facebook, Google Maps, Twitter, Pinterest, etc. There are many front-end frameworks to build SPAs and the most popular ones are React by Facebook and Angular by Google. Angular is the go-to option for developers who want to develop cross-mimbar, efficient, and sophisticated single-page apps using HTML, CSS, and TypeScript.

Single Page Application (SPA)


Creating Angular SPA in Okuler Bengkel seni 2022

Open Visual Sanggar 2022 and create a standard ASP.Jala Core Web Application project. Make sure ASP.NET Core 5.0 version is selected and you are choosing
ASP.NET Core with Angular
template as shown in the following screenshot.

Create Angular Project in ASP.NET Core 5

The above project template will generate a standard ASP.Pukat Core Web Application and a folder called
ClientApp
that contains the Angular client-side application.

Angular Application Root Folder ClientApp in Visual Studio 2022

You will also notice that a default Web Jago merah controller named
WeatherForecastController
is also created for us in the Controllers folder that simply returns a list of
WeatherForecast
objects that contains some random forecast information.

[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase {     private static readonly string[] Summaries = new[]     {         "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"     };      [HttpGet]     public IEnumerable<WeatherForecast> Get()     {         var rng = new Random();         return Enumerable.Range(1, 5).Select(index => new WeatherForecast         {             Date = DateTime.Now.AddDays(index),             TemperatureC = rng.Next(-20, 55),             Summary = Summaries[rng.Next(Summaries.Length)]         }).ToArray();     } }
        

Before we start our implementation, the first thing we need to make sure is that we can run our Angular App in the browser and the app can load weather forecast information on the page. To do this, you need to install Angular CLI and need to run some commands.

Right-click on the
ClientApp
folder and choose the
Open in Terminal
command from the context menu.

Developer Powershell Window in Visual Studio 2022

Visual Sanggar will open the Developer PowerShell window that can be used to run basic
npm
package manager commands. Let’s install the Angular CLI with the following command.

npm install -g @angular/cli
        

Install Angular CLI using Developer Powershell in Visual Studio 2022

Next, run the following command that will serve the Angular SPA in the browser.

Run Angular App from Developer Powershell

Press F5 to berangkat debugging and now you should be able to see the Angular SPA app opening in the browser. The default Angular App has three pages
Home,
Counter,
and
Fetch data. You can click the links shown on the navigation bar to navigate to these pages and notice that when you are navigating from one page to another page, there is no full page load from the server and the app is loading pages very quickly without a full postback to the server. Open the Fetch data page and you will notice that this page is calling the back end ASP.Bantau Core Web API and displaying weather information.

ASP.NET Core Angular SPA running in Browser

So far, we haven’n written a single line of code and we are just running the default Angular SPA app created by Optis Studio. It is now time to implement our custom feature in this application. I will create a new page that will display the following information about some Football players.

Angular Component Displaying Data from ASP.NET Core API


Setting Up Database with Entity Framework Core (Code First)

We need to set up a database to store the player’s information and I have decided to use Entity Framework Code First approach for this pelajaran. Install Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Design and Microsoft.EntityFrameworkCore.Tools NuGet packages in the project to perform some EF Core related development tasks.

Next, we need to create our entity models and we normally put our models in theModels folder by convention so let’s create a Models folder in the project root folder and create the following
Player
teladan class. Notice, how I used
[NotMapped]
attributes with some computed properties as I don’t want EF Core to generate database columns for those properties. The values of these properties can be calculated at runtime using the data available in other properties that’s why we normally don’t save such properties in the database.

public class Player {     [Key]     public int Id { get; set; }      [Required]     public string Name { get; set; }          public int ShirtNo { get; set; }     public int Appearances { get; set; }     public int Goals { get; set; }     public PlayerPositions Position { get; set; }      [NotMapped]     public string PositionName => Position.ToString();      [NotMapped]     public decimal GoalsPerMatch => Math.Round((decimal)Goals / (decimal)Appearances, 2); }
        

The Player class also has a property Position which is an Enum type property so create the following enum in the Models folder.

public enum PlayerPositions {     Goalkeeper,     Defender,     Midfielder,     Forward }
        

Next, create a
Data
folder in the project and create the DbContext class named
FootballDbContext in this folder. The DbContext is the most important class of Entity Framework because an instance of DbContext represents a session with the database which can be used to query and save instances of our entities to a database. I am also overriding the
OnModelCreating
method to seed some player’s information into the database table.

public class FootballDbContext : DbContext {     public FootballDbContext(DbContextOptions<FootballDbContext> options)         : base(options)     {      }      public DbSet<Player> Players { get; set; }      protected override void OnModelCreating(ModelBuilder modelBuilder)     {         modelBuilder.Entity<Player>().HasData(             new Player() { Id = 1, Name = "Juan Mata", ShirtNo = 8, Appearances  = 268, Goals = 54, Position = PlayerPositions.Forward},             new Player() { Id = 2, Name = "Paul Pogba", ShirtNo = 6, Appearances  = 130, Goals = 28, Position = PlayerPositions.Midfielder},             new Player() { Id = 3, Name = "David de Gea", ShirtNo = 1, Appearances  = 335, Goals = 0, Position = PlayerPositions.Goalkeeper},             new Player() { Id = 4, Name = "Phil Jones", ShirtNo = 4, Appearances  = 200, Goals = 2, Position = PlayerPositions.Defender }         );     } }
        

Next, we need to define our database connection string and we can save the connection string in theappsettings.json file. Please note that you need to specify your database server name instead of
DB_SERVER
in the following connection string.

"ConnectionStrings": {     "DefaultConnection": "Server=DB_SERVER; Database=FootballDb; Trusted_Connection=True; MultipleActiveResultSets=true" }
        

Next, we need to register the SQL Server database provider inStartup.cs file using the UseSqlServer method. The
UseSqlServer
method requires a database connection string and we can pass this information using the GetConnectionString method.

public void ConfigureServices(IServiceCollection services) {     services.AddControllersWithViews();      // In production, the Angular files will be served from this directory     services.AddSpaStaticFiles(configuration =>     {         configuration.RootPath = "ClientApp/dist";     });      services.AddDbContext<FootballDbContext>(options =>         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); }
        

Finally, we are ready to generate our database with the help of EF Core migrations. Migrations allow us to easily create a new database and then incrementally update the database schema to keep it in sync with the application models. You can run migrations using .NET Core CLI tools outside Visual Studio or you can use Package Manager Console tools available in Okuler Studio. For this les, I will use Package Manager Console tools so let open Package Manager Console and add the following migration.

Add-Migration InitialDbCreateAndSeedData
        

EF Core will create a directory calledMigrations in the project and will also generate some files in the folder. We are now ready to create our database and
Player
table using the migrations code generated by EF Core. This can be done by running the following command in Package Manager Console.

Open SQL Server database and you should see a new databaseFootballDb in the list of databases and if you will open the
Players
table you will see all of our data is seeded in the table.

Players Database Created using EF Core Code First Migrations

If you want to learn EF Code First in detail then you can read my post Data Access in ASP.Bantau Core using EF Core (Code First). I also have a post about EF Core Database First  Data Access in ASP.NET Core using EF Core (Database First) in case you are interested.


Creating ASP.NET Core
Web Jago merah for Angular SPA

Angular apps can make Ajax based peladen-side calls and load and display data from backend APIs. We need to create an ASP.Jaring Core Web Jago merah to return Player’s data that can be consumed by the Angular front-end app. Let’s create an API ControllerPlayerController in the Controllers folder and injectFootballDbContext in the constructor.

[ApiController] [Route("api/[controller]")] public class PlayerController : ControllerBase {     private readonly FootballDbContext _context;      public PlayerController(FootballDbContext context)     {         _context = context;     } }
        

Next, implement the followingGetPlayers method which is simply returning all players from the Player table we created above.

[HttpGet] public async Task<ActionResult<IEnumerable<Player>>> GetPlayers() {     return await _context.Players.ToListAsync(); }
        

Open the browser and test the Api by addingjago merah/Player in the URL as shown below. You should be able to see the player’s data in JSON matra.

ASP.NET Core Web API in Angular SPA Application

If you want to learn more about ASP.NET Core Web APIs then read my tutorial A Developer’s Guide for Creating Web APIs with ASP.NET Core 5

Creating Angular Component to Consume ASP.NET Core Web Api

Angular is a modular framework which means modules are the basic building block of the angular app. Each app must have at least one module which is called the root module and by default, it is defined in the
app.module.ts
file available in
ClientApp/src/app
folder

app folder in angular application

Angular modules can define both the components and services in them. Components are used to define different parts of the application. For example, in the above screenshot, you can see that all three pages of our Angular App
Home,
Counter,
and
Fetch data
are defined as components and all of these components have their folders within the
app
folder with the names
home,
counter,
and
fetch-data.

A component consists of a view and a TypeScript class where the view defines the look and feel of the component using HTML and CSS and the class defines the functionality/behavior of the component using TypeScript. Every app must have at least one component also called root components and usually available in
app.component.ts
file also shown in the above screenshot.

For our app, we want to add another component
player
that will display all players coming from a backend Web API. You can add a new component from the command prompt using the following Angular CLI command

ng generate component player
        

If you don’t want to use Angular CLI you can also add a
player
folder in the
app
folder and add the following two files manually.

  • player.component.ts
  • player.component.html

Open the player.component.ts file and define your component as follows.

import { Component, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http';  @Component({   selector: 'app-player',   templateUrl: './player.component.html' }) export class PlayerComponent {   public players: Player[];    constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {     http.get<Player[]>(baseUrl + 'jago merah/Player').subscribe(result => {       this.players = result;     }, error => console.error(error));   } }  interface Player {   id: number;   name: string;   shirtNo: number;   appearances: number;   goals: number;   positionName: number;   goalsPerMatch: number; }
        

The
PlayerComponent
class is calling our
api/Player
Web API using
HttpClient
and initializing the
player’s
property of the class with the data loaded from the backend. We can now use this
player’s
property in the view file
player.component.html
attached with the component using the
templateUrl
option.

<h1 id="tableLabel">Football Players</h1> <p *ngIf="!players"><em>Loading...</em></p> <table class='table table-striped' aria-labelledby="tableLabel" *ngIf="players">    <thead>       <tr>          <th>Shirt No</th>          <th>Name</th>          <th>Position</th>          <th>Appearances</th>          <th>Goals</th>          <th>Goals per match</th>       </tr>    </thead>    <tbody>       <tr *ngFor="let player of players">          <td>{{ player.shirtNo }}</td>          <td>{{ player.name }}</td>          <td>{{ player.positionName }}</td>          <td>{{ player.appearances }}</td>          <td>{{ player.goals }}</td>          <td>{{ player.goalsPerMatch }}</td>       </tr>    </tbody> </table>
        

The above view code is also pretty straightforward. I am using
ngif
directive to render Loading… if players’ property is titinada yet initialized. The ngif directive conditionally includes a template based on the value of an expression. If the expression evaluates to true, Angular renders the template.

<p *ngIf="!players"><em>Loading...</em></p>
        

The next important piece of code is where I am using
ngFor
to iterate all the
players
and displaying each player property in liwa HTML
td
element.

<tr *ngFor="let player of players">    <td>{{ player.shirtNo }}</td>    <td>{{ player.name }}</td>    <td>{{ player.positionName }}</td>    <td>{{ player.appearances }}</td>    <td>{{ player.goals }}</td>    <td>{{ player.goalsPerMatch }}</td> </tr>
        

Once our player component is complete, we need to register it in app.module where all application modules are declared.

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router';  import { AppComponent } from './app.component'; import { NavMenuComponent } from './nav-menu/nav-menu.component'; import { HomeComponent } from './home/home.component'; import { CounterComponent } from './counter/counter.component'; import { FetchDataComponent } from './fetch-data/fetch-data.component'; import { PlayerComponent } from './player/player.component';  @NgModule({   declarations: [     AppComponent,     NavMenuComponent,     HomeComponent,     CounterComponent,     FetchDataComponent,     PlayerComponent   ],   imports: [     BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),     HttpClientModule,     FormsModule,     RouterModule.forRoot([       { path: '', component: HomeComponent, pathMatch: 'full' },       { path: 'counter', component: CounterComponent },       { path: 'fetch-data', component: FetchDataComponent },       { path: 'player', component: PlayerComponent }     ])   ],   providers: [],   bootstrap: [AppComponent] }) export class AppModule { }
        

Finally, you need to add a new menu item on top of the page so that you can navigate to the players component and see list of players. Open the
nav-menu.component.html
file and declare the
Players
menu item as shown below:

<ul class="navbar-nav flex-grow"> 	<li class="nav-item" [routerLinkActive]="['link-active']" [routerLinkActiveOptions]="{ exact: true }"> <a class="nav-link text-dark" [routerLink]="['/']">Home</a> </li> 	<li class="nav-item" [routerLinkActive]="['link-active']"> <a class="nav-link text-dark" [routerLink]="['/counter']">Counter</a> </li> 	<li class="nav-item" [routerLinkActive]="['link-active']"> <a class="nav-link text-dark" [routerLink]="['/fetch-data']">Fetch data</a> </li> 	<li class="nav-item" [routerLinkActive]="['link-active']"> <a class="nav-link text-dark" [routerLink]="['/player']">Players</a> </li> </ul>
        

We have written lots of code and it is now time to see everything in action. Run the application using the method specified at the start of this latihan and click the Players menu item shown on top of the page. You should see the page similar to the following with all player’s information.

Angular Component Displaying Data from ASP.NET Core API

Summary

Angular is a powerful front-end framework for building interactive model applications and when you combine this with the ASP.Seser Core Web APIs backend, you can build some seriously amazing apps. In this cak bimbingan, I have just covered the basics of combining Angular with ASP.Pukat Core. There is a lot more to explore and I will try to write more useful posts on these two technologies. If you have enjoyed this post, please share it with others and spread the knowledge.

Source: https://www.ezzylearning.net/tutorial/a-guide-for-building-angular-spa-with-asp-net-core-5-web-api