In the last module we finally got our application up and running and when we run it we see a WeatherForecast component with five WeatherForecasts for the next five days. And we didn’t even do anything in either of the projects to set this up. All we did was a little minor configuration to get both projects communicating with each other.

It turns out that an ASP.Net Core Web API project template has one sample API Rest Service built in out of the box: WheatherForecast. And the Standalone TypeScript Angular project happens to have a call in the root (and only existing) component to a Rest Service called WeatherForcast. Hmm… Almost like they planned it. And I’m sure they did.
Let’s take the opportunity to understand the existing out of the box component and it’s call to the Web API service. This will give us the chance to learn the basic patterns of a component and it’s calling of a web service. We’ll also review the startup and bootstrapping of an Angular application along the way to get a complete picture of the existing application as it stands at this point.
The Angular Entry Point: main.ts
As you might recall from the Angular chapter in Chapter 6, the entry point for an Angular application is the TypeScript file, “main.ts”. Open up the code in FredsCars/src/maint.ts and let’s take a look.
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
The important thing to know here is that this file, being the entry point to the application is responsible for bootstrapping the root module of the application, AppModule.
The Application Root Module: AppModule
Once maint.ts bootstraps AppModule, AppModule itself is then responsible for bootstrapping or loading the root component called AppComponent.
An Angular Module is a place where pieces of code be it components, directives, services or even other modules can be grouped together in order to provide some form of functionality that can be reused in many places throughout the application.
Let’s break down the code in AppModule and take a better look. Open up the file FredsCars/src/app/app.module.ts.
The top part of the code is a series of import statements. We can think of these as being similar to using statements at the top of C# classes that import namespaces. These import statements however import JavaScript modules. The first three import statements import Angular Module classes from JavaScript modules.
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
Remember from Chapter 6 that the package.json file lists all of the dependencies to download and install in the node_modules folder. When we created the Standalone TypeScript Angular project, it ran the “ng new” command behind the scenes to create the Angular application and installed all of these dependencies. So when the top import statement above goes to import the HttpClientModule, Angular can find it in node_modules/@angular/common/http.

The last import statement imports a component, specifically, the root component called AppComponent.
import { AppComponent } from './app.component';
The pathway provided for the import is given after the “from” keyword. The period-forward slash characters './'
say from the folder I exist in or from the current folder, find and load app.component. Notice there is no ‘.ts’ tacked on to the end of the pathway’s filename.

The second part of the code is the actual AppModule class decorated with NgModule.
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule, HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
The @NgModule
decorator marks the AppModule
class as an Angular Module. Remember an Angular module is where we can group together functionality to be reused throughout the application. So, AppModule being the root module is where we register all the functionality; other modules, components, services and so on we will need throughout the application.
The declarations property of NgModule is an array of components that can be used throughout the Angular application. So far we are only declaring AppComponent. And we are able to do that because we imported it in the import statements at the top of the file.
The imports section lists the Modules we are making available to the Angular Application. Here we list BrowserModule and HttpClientModule to be available. Again we are able to do this because we imported these dependancies in the import statements at the top of the file.
We have not yet listed any available services in the providers section.
The last property in NgModule, and the most important aspect of NgModule we are looking at here for the moment is the bootstrap property. This property instructs AppModule to bootsrap or load the top-level component, or the root component called AppComponent.
Understand that what we are really doing in the declarations, imports, and providers sections of NgModule is registering all of our components, modules, and services in our DI (Dependancy Injection) Container to be available to other building blocks of code as they are needed.
The Application Root Component: AppComponent
Now that AppModule had kindly loaded up AppComponent for us, let’s take a look. Open up FredsCars/src/app/app.component.ts
import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public forecasts?: WeatherForecast[];
constructor(http: HttpClient) {
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
}
title = 'FredsCars';
}
interface WeatherForecast {
date: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
This is the first Angular component we are looking at in our FullStack application. At first glance it might seem like a lot of code. But stick with me. it’s really not that bad once we attack it one piece at a time.
The import(s) section
The first section again, as usual is the top imports section:
import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
Here we are importing the HttpClient
class so we can use it in the constructor later in the code. And we are importing the Component
class so we can mark the AppComponent
class as an Angular Component. We’ll be able to make use of these two pieces of functionality because remember we registered the module that the HttpClient
class lives in (HttpClientModule
) back in AppModule
and we can use the Component
decorator just by having the import Component from @angular/core
statement in the top imports section. We did not need to register Component
back in AppModule
. We can grab it right out of @angular/core
namespace with the top import statement.
Component Decorator
Next we mark the AppComponent class as an Angular component with the Component decorator.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
The Component decorator has three properties.
- The selector property is saying insert me as a component anywhere you see an <app-root> html element.
Once the compilation process is complete after you run the application in debug mode and the Angular develoment tools start up your browser, Angular serves up index.html from the FredsCars/src folder. This file will contain the <app-root> element to insert AppComponent.
<body>
<app-root></app-root>
</body>
2. The templateUrl property sets the path and filename of the html file to use as the view template for the component.
3. The styleUrls property has as it’s value an array of CSS files we can use for this component. Right now just one file is declared, ‘app.component.css’ and it is empty to start with.
The export keyword on the AppComponent class declaration makes it available to import from a JavaScript module throughout the rest of the application. This is how AppModule was able to import it and declare it as a component in the declarations section of it’s NgModule decorator.
Making the class available to import from a JavaScript module.
export class AppComponent
Importing the class from a JavaScript module.
import { AppComponent } from './app.component';
Working with Interfaces
We’ll go over the rest of the class in a moment. But, first I want to skip down to the bottom of the code and talk about Interfaces. Interfaces are a way to work with results returned from a Rest Service call in a strongly typed fashion instead of working directly with the JSON results. We’ll see this made use of when we return to inspecting the rest of the AppComponent class. But for now take a look at the interface decleration at the bottom of the code.
interface WeatherForecast {
date: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
This interface is describing what each WeatherForecast object should look like in the JSON results returned from the ASP.Net Angular Core Web API application’s WeatherForecast Rest Service that we looked at in the previous module, Add the ASP.Net Core Web API project.
Each WeatherForecast object should contain four properties:
- date: of type string
- temperatureC: of type number
- temperatureF: of type number
- summary: of type string
Now that we understand a little more about interfaces, we can return to inspecting the rest of the actual AppComponent class.
Getting Results
The rest of the AppComponent class is about the actual meat of the work this component is supposed to do. Make a call to the back-end, get the JSON result and feed it to the HTML Template in order to render in a readable fashion for the user.
export class AppComponent {
public forecasts?: WeatherForecast[];
constructor(http: HttpClient) {
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
}
title = 'FredsCars';
}
The first statement in the code above declares a public variable called forecasts of type WeatherForcast Array.
public forecasts?: WeatherForecast[];
Next we have the constructor of the AppComponent class.
constructor(http: HttpClient) {
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
}
The constructor receives as a parameter an instance of the HttpClient service. This service is used to make an HTTP request.
Here is the whole HTTP request call within the constructor.
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
Let’s inspect the parts that make up this call.
First, we are specifying that we want to make an HTTP Get request that returns a strongly typed JSON result of a WeatherForecast array. This part is in bold in the code below.
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
Next we feed the http.get() method a single value for the URL parameter.
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
The HttpClient knows how to find the complete back-end Web API URL address since we defined it back in proxy.config.js:
const PROXY_CONFIG = [
{
context: [
"/weatherforecast",
],
target: "https://localhost:40443",
secure: false
}
]
So the url parameter of ‘/weatherforcast’ in the http.get() call will translate to:
https://localhost:40443/weatherforecast
Ok, so we’ve made the http get call. So in the next part of the statement we are going to listen for the results by chaining on a subscribe method to the call.
http.get<WeatherForcast[]>
happens to be an observable and if you’ve ever done any asyncronous programming this is like a promise to return a WeatherForcast[]
result. This would be like a Task[WeatherForcast[]>
result in C#. But an Observable has many more features and is more robust then a promise.
Ok, so let’s hone in on the subscribe method and take a look.
constructor(http: HttpClient) {
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
}
The subscribe method is listening for the JSON result of the http.get()
web api call and once received subscribe()
will use a lambda expression to set the class’ forecasts
property value to the JSON result; An array of weatherForcast
objects defined in our interface. We also pass the subscribe()
method a second lamda function to execute in case of an error which will just log any error to the console.
For completeness I’ll mention the last statement in the class.
title = 'FredsCars';
There is a property named title set to FredsCars. The project template seems to have taken the name of our project and used that since this is the root, home, or top level component of the application.
Well that’s it. We’ve covered the whole AppComponent class. I hope that wasn’t too bad but I really want us to get a grip on the basic patterns here since we will have to modify the templates and start writing our own code eventually.
One would probably guess that the next thing to cover would be the HTML template, app.component.html. But let’s not just assume the results we got back from the http.get()
web api call above was just magic and treat it like a black box. Let’s trace it through and then we will return to the View template.
The Web API Controller
In the last section we walked through what the meat of AppComponent class does in it’s constructor.
constructor(http: HttpClient) {
http.get<WeatherForecast[]>('/weatherforecast').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));
}
It makes an HTTP GET request to the WeatherForecast Web API in the FredsCarsAPI project. Let’s look at the code that is actually responsible for generating and returning the JSON results from the back-end to the front-end in the Web API WeatherForecast controller. Open FredsCarsAPI/controllers/WeatherForecastController.cs and let’s have a look.
using Microsoft.AspNetCore.Mvc;
namespace FredsCarsAPI.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
As usual this may look like a lot of code to understand. But let’s just break it down again one piece at a time.
We start out by declaring a class that inherits from the ControllerBase class and is decorated with two attributes.
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
Recall in “Chapter 3: ASP.Net MVC Core – Models, Views, and Controllers”, our controllers inherit from the Controller class because the MVC controllers needed support for views. Here our Web API controllers do not need support for views so we can use the more light weight ControllerBase class.
The ApiController attribute marks the class as a Web Api Controller. We don’t technically need this attribute. But by using it we don’t have to manually convert our results into JSON format and we don’t have to perform server side validation with ModelState.IsValid
.
The Route attribute defines the route or URL address needed to make a request from this Web API controller. The keyword controller in brackets ‘[controller]
‘ sets the route to the name of the controller:
/WeatherForecast
Notice ‘Controller’ is not tacked onto the end of WeatherForecast as in:
/WeatherForecastController
Once we get inside the class the first statement declares a string array called Summaries.
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
Next we have a private ILogger member and our constructor using the Dependency Injection pattern which we should be very familiar with by now from “Part 2: ASP.Net Core: Dynamic Applications, Data and Frameworks“.
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
And finally we have the actual HTTP Get method itself.
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
The HttpGet attribute marks the Get action as an HttpGet request as opposed to an HttpPost request.
[HttpGet(Name = "GetWeatherForecast")]
We also learned the concept of HTTP Get and Post methods back in part two.
The call from Angular’s AppComponent constructor, http.get<WeatherForecast[]>('/weatherforecast')
, is enough to find the Get()
method here because /weatherforecast
locates this controller as declared by the Route attribute above the controller declaration, and then finds this Get()
action because it is marked by an HttpGet
attribute. Not because the name of the action is Get. The name of this action could be ApplesAndOranges and would have the same affect:
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> ApplesAndOranges()
Let’s not worry about the Name parameter to the HttpGet attribute for right now. We’ll see what this does in later modules.
Returning Results
The method signature itself describes a method that returns an IEnumerable of WeatherForecast. We can think of this as a collection of WeatherForecast objects for now.
public IEnumerable<WeatherForecast> Get()
The body of the class is made up of one return statement but the template cleverly fits everything needed into this one statement to return an Array of WeatherForecast objects.
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
After the return keyword, the statement uses Enumerable.Range(1, 5)
to generate a sequence of numbers 1 through 5.
It then chains on a LINQ Select method to iterate through the generated numbers 1 – 5 and project out a WeatherForecast object for each number iteration and uses a lambda expression to build each of those objects.
The lambda expression takes in the generated number from the current iteration of Enumerable.Range(1,5)
as a parameter called index
and passes it to the body of the lambda expression after the goes-into operator '=>'
.
The body of the expression creates a new WeatherForcast object and sets three out of the four WeatherForecast properties; Date
, TemperatureC
, and Summary
. The WeatherForecast object itself uses the TemperatureC (Celsius) to calculate its TemperatureF (Fahrenheit) value.
The Date
property is set to 1, 2, 3, 4, and 5 days from the current date by adding the value from the lambda expression’s index
parameter based on the current iteration using the AddDays
method of the DateTime.Now
object.
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index))
TemperatureC is set to a random value between -20 and 55.
TemperatureC = Random.Shared.Next(-20, 55)
Summary is randomly set to one of the options of the Summaries array we saw declared at the top of the class.
- Freezing
- Bracing
- Chilly
- Cool
- Mild
- Warm
- Balmy
- Hot
- Sweltering
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
Finally the return statement takes the IEnumerable<WeatherForecast>
collection it has built up and converts it to an array using the ToArray()
method which is possible because an Array
inherits from IEnumerable
in .Net.
We might expect our results to look something like this using Pascal case based on our C# Weatherforecast object:
[
{Date: "2023-07-21", TemperatureC: TemperatureF: 84, Summary: "Balmy"}
{Date: "2023-07-22", TemperatureC: TemperatureF: 64, Summary: "Mild"}
{Date: "2023-07-23", TemperatureC: TemperatureF: 64, Summary: "Bracing"}
{Date: "2023-07-24", TemperatureC: TemperatureF: 98, Summary: "Warm"}
{Date: "2023-07-25", TemperatureC: TemperatureF: 120, Summary: "Chilly"}
]
The C# WeatherForecast object that is being used to create each object in the returned array looks like this and can be found in the root of the FredsCarsAPI project.
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
But remember! Because we marked the WeatherForecastController class with the ApiController attribute, the HTTP GET method will automatically convert the results to JSON format for us. So the results will look more like this in camel case:
[
{"date":"2023-07-21","temperatureC":29,"temperatureF":84,"summary":"Balmy"},
{"date":"2023-07-22","temperatureC":18,"temperatureF":64,"summary":"Mild"},
{"date":"2023-07-23","temperatureC":18,"temperatureF":64,"summary":"Bracing"},
{"date":"2023-07-24","temperatureC":37,"temperatureF":98,"summary":"Warm"},
{"date":"2023-07-25","temperatureC":49,"temperatureF":120,"summary":"Chilly"}
]
And, remember we defined our WeatherForecast interface back in AppComponent in the Angular Project to match and catch the type of JSON results we are expecting:
interface WeatherForecast {
date: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
Well I think we’ve done a pretty good trace here. Let’s finish it up and finally take a look back at the HTML Template.
Back to Angular: Render the Results
Now that we’ve done all the work, and by we I really mean the templates, to make a call to the back-end, get the results, and fill our variables in our component with data, we can easily render the JSON results into a more readable and usable fashion in HTML; The most important variable here being the forcasts
variable of type WeatherForcast
Array in AppComponent
.
public forecasts?: WeatherForecast[];
Again, at this point we can expect the value of forecasts to look like this:
[
{"date":"2023-07-21","temperatureC":29,"temperatureF":84,"summary":"Balmy"},
{"date":"2023-07-22","temperatureC":18,"temperatureF":64,"summary":"Mild"},
{"date":"2023-07-23","temperatureC":18,"temperatureF":64,"summary":"Bracing"},
{"date":"2023-07-24","temperatureC":37,"temperatureF":98,"summary":"Warm"},
{"date":"2023-07-25","temperatureC":49,"temperatureF":120,"summary":"Chilly"}
]
Let’s inspect the AppComponent’s Template file. Open FredsCars/src/app/app.component.html. The code should look like the following:
<h1 id="tableLabel">Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
<p *ngIf="!forecasts"><em>Loading... Please refresh once the ASP.NET backend has started. See <a href="https://aka.ms/jspsintegrationangular">https://aka.ms/jspsintegrationangular</a> for more details.</em></p>
<table *ngIf="forecasts">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let forecast of forecasts">
<td>{{ forecast.date }}</td>
<td>{{ forecast.temperatureC }}</td>
<td>{{ forecast.temperatureF }}</td>
<td>{{ forecast.summary }}</td>
</tr>
</tbody>
</table>
The first two lines just show a heading and a paragraph describing what this component does.
<h1 id="tableLabel">Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>

The third line is a paragraph element with an ngIf
structural directive:
<p *ngIf="!forecasts"><em>Loading... Please refresh once the ASP.NET backend has started. See <a href="https://aka.ms/jspsintegrationangular">https://aka.ms/jspsintegrationangular</a> for more details.</em></p>
ngIf
here has !forecasts
as its value so this paragraph will render only if the forecasts
property is null in app.component.ts. This can happen if the Angular project compiles and launches the browser window and renders before the ASP.Net Core Web API project can compile and run even though we set the Standalone TypeScript Angular project to start first back when we were configuring the solution.

If this happens just refresh the browser window once the ASP.Net Core project starts and shows it is listening on the port we configured in our setup.

The next line is the opening tag of a Table element with another ngIf
directive. This time it says to display the table element if the forecasts
property is not empty or null meaning the call to the Rest Service and receipt of the JSON results was a success.
<table *ngIf="forecasts">
Next we set up our table header columns:
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
And finally we lay out the table body with an ngFor
directive and close the table element:
<tbody>
<tr *ngFor="let forecast of forecasts">
<td>{{ forecast.date }}</td>
<td>{{ forecast.temperatureC }}</td>
<td>{{ forecast.temperatureF }}</td>
<td>{{ forecast.summary }}</td>
</tr>
</tbody>
</table>
ngFor
makes any element it is applied to like the tr
element a template and repeats that template for every object in a collection like our forecasts
WeatherForecast array.
The let forecast of forecasts
expression assigns each WeatherForecast object to a variable called forecast so we can lay out its date, temperatureC, temperatureF, and summary properties in table columns.

And that’s it. We now know how the simple, yet complete sample WeatherForecast component works in both the front-end and back-end from top to bottom. We are well prepared now to start writing our own code and start creating our Full-Stack FredsCars application.
What’s Next
In the next several modules we’ll spend some time creating a Web API controller called VehiclesController to return a list of Cars, Trucks, and Jeeps in JSON format so we can use it to display that data in an HTML Table within an Angular component.