We’ve spent a good amount of time so far setting up our initial solution and projects as well as wiring and configuration. We also took a pretty extensive look at how the initial out of the box WeatherForecast Web API service and Angular component work.
It’s time now to finally role up our sleeves and start writing our own code. I know… Finally! Well here we go.
The Vehicles Web Service
In this module we are going to create a Vehicles Web Service. To do so we will use an API controller called VehiclesController. I am going to return just enough data in JSON format to get us started. And we won’t even need a database up front. We’ll get to creating the DB in a little while. I just want to have enough data to work with to get something up and running in an Angular component which at this point will be some mock data we spin up.
The Domain Model
The first thing we should to do is start to design our Domain Model. To start with all we need is a Vehicle entity class and a VehicleType entity class both represented as C# POCOs (Plain Old C# Objects) in our Web API project.
Create a folder named Models in the root of the FredsCarsAPI project.
In the new Models folder, add a class file named VehicleType.cs and replace it’s contents with the code shown below.
namespace FredsCarsAPI.Models
{
public class VehicleType
{
public int Id { get; set; }
// ["Car", "Truck", "Jeep"]
public string Name { get; set; } = string.Empty;
}
}
In the Models folder add a second class called Vehicle.cs with the code below.
namespace FredsCarsAPI.Models
{
public enum Status
{
New,
Used
}
public class Vehicle
{
public int Id { get; set; }
public Status Status { get; set; }
public string Year { get; set; } = string.Empty;
public string Make { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
public string Color { get; set; } = string.Empty;
public double Price { get; set; }
public string VIN { get; set; } = string.Empty;
public int VehicleTypeId { get; set; }
public VehicleType VehicleType { get; set; } = null!;
}
}
Create the Controller
Right click the Controllers folder and select Add –> Controller. In the “Add New Scaffolded Item dialogue, click API on the left under Installed and on the right select “API Controller – Empty”.

In the “Add New Item” dialogue, set the name to “VehiclesController.cs” and click Add.

The resulting autogenerated code for the API Controller is shown below. We should be very familiar with this code since we went over the ApiController and Route attributes as well as the ControllerBase class inherited from here extensively in the last module.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace FredsCarsAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class VehicleController : ControllerBase
{
}
}
Now let’s add the HttpGet method. Modify VehiclesController.cs with the following code. The additions are shown in bold blue text.
using FredsCarsAPI.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace FredsCarsAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class VehiclesController : ControllerBase
{
[HttpGet]
public IEnumerable<Vehicle> GetVehicles()
{
var vehicleTypes = new List<VehicleType>()
{
new VehicleType { Id = 1, Name = "Car" },
new VehicleType { Id = 2, Name = "Truck" },
new VehicleType { Id = 3, Name = "Jeep" }
};
var vehicles = new List<Vehicle>()
{
// Cars
new Vehicle {
Id = 1,
Status = Status.New,
Year = "2021",
Make = "Dodge",
Model = "Challenger",
Color = "Frostbite",
Price = 64164,
VIN = "2C3CDZFJ8MH631199",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)!
},
new Vehicle {
Id = 2,
Status = Status.Used,
Year = "2020",
Make = "Ford",
Model = "Escape",
Color = "Oxford White",
Price = 22999,
VIN = "1FMCU0F63LUC25826",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)!
},
new Vehicle {
Id = 3,
Status = Status.New,
Year = "2021",
Make = "Dodge",
Model = "Durange",
Color = "Black",
Price = 50557,
VIN = "1C4RDJDG5MC837730",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)!
},
new Vehicle {
Id = 4,
Status = Status.New,
Year = "2021",
Make = "Nissan",
Model = "Niro",
Color = "Blue",
Price = 24960,
VIN = "2XYZT67JTF24AZG856",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)!
},
new Vehicle {
Id = 5,
Status = Status.New,
Year = "2021",
Make = "Kia",
Model = "Stinger",
Color = "Gray",
Price = 36090,
VIN = "6FG146B89624AZ7952",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)!
},
new Vehicle {
Id = 6,
Status = Status.New,
Year = "2021",
Make = "Kia",
Model = "Stinger",
Color = "Gray",
Price = 36090,
VIN = "6FG146B89624AZ7952",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)!
},
// Trucks
new Vehicle {
Id = 7,
Status = Status.New,
Year = "2022",
Make = "Ram",
Model = "Crew Cab",
Color = "Black",
Price = 68400,
VIN = "3C6UR5DL8NG157035",
VehicleTypeId = 2,
VehicleType = vehicleTypes.Find(v => v.Id == 2)!
},
new Vehicle {
Id = 8,
Status = Status.Used,
Year = "2017",
Make = "Ram",
Model = "Crew Cab",
Color = "Red",
Price = 33000,
VIN = "1C6RR7PT0HS814596",
VehicleTypeId = 2,
VehicleType = vehicleTypes.Find(v => v.Id == 2)!
},
// Jeeps
new Vehicle {
Id = 9,
Status = Status.New,
Year = "2022",
Make = "Jeep",
Model = "Compass",
Color = "White",
Price = 34980,
VIN = "3C4NJDFB5NT114024",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)!
},
new Vehicle {
Id = 10,
Status = Status.New,
Year = "2022",
Make = "Jeep",
Model = "Compass",
Color = "Red",
Price = 39275,
VIN = "3C4NJDCB1NT118172",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)!
},
new Vehicle {
Id = 11,
Status = Status.New,
Year = "2022",
Make = "Jeep",
Model = "Grand Cherokee",
Color = "Pearlcoat",
Price = 53575,
VIN = "1C4RJKBG5M8201121",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)!
},
new Vehicle {
Id = 12,
Status = Status.New,
Year = "2021",
Make = "Jeep",
Model = "Wrangler Sport S",
Color = "Green",
Price = 40940,
VIN = "1C4GJXAN0MW856433",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)!
},
};
return vehicles;
}
}
}
Test the Vehicles Web Service
Let’s run the FredsCarsAPI project in debug mode and take a look at our quick and dirty results. In Solution Explorer, right click on the FredsCarsAPI project and select “Debug –> Start New Instance”.

Once you see the console window is up and hosting the Web API project, open a browser and go to the following URL Address:
https://localhost:40443/api/vehicles
You should see the following results.

We can see that we have a major success! We are getting back a JSON array of Vehicle Objects we defined with our C# POCO classes. And, .Net modified all of our objects from C# pascal case to JSON/JavaScript camel case like we talked about in the previous module. This was actually very quick and easy to do now that we are starting to get a better idea of how everything flows. But the results aren’t very pretty to look at.
Testing Web Services with Swagger
There are ways to configure better indenting and readability in the pipeline configuration in program.cs. But let’s not worry about that for the moment. Right now I want to talk about a tool called Swagger that will let us test all our web services. Swagger can autogenerate Web API documentation for our application so we don’t have to write it by hand for other developers to be able to use our services.
Swagger is automatically added by the ASP.Net Core Web API template we used earlier on to add the FredsCarsAPI project to the solution.
Open up program.cs from the root of the FredsCarsAPI project and take a look.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
You can see the important lines to add Swagger services to the application in the code above in bold and blue font. First the Swagger services are added to the DI (Dependency Injection) Container in the Add Services section. Then the Swagger middleware is added into the pipeline. Notice this middleware is only added in if the application is running in Development mode. We could open it up to production later but we need to think about how we approach this because you can execute post, put, and delete methods as well as get methods from Swagger so any user with a little knowledge could easily alter our data.
Swagger Quick Tour
Point your browser to the following URL:
https://localhost:40443/swagger/index.html
Swagger UI will open up for our FredsCarsAPI project and you’ll see Swagger has generated documentation for both of the existing API controllers; Vehicles and WeatherForecast.
Go ahead and click the Get method for Vehicles.

Once the Vehicles Get section is expanded you can see Swagger has done a pretty amazing job with the documentation. There are of course no parameters since this is a Get method, a successful result would have a code of 200/Success, and at the very bottom is the schema of what the JSON response would look like, an array of Vehicle objects. Click the “Try it out” button to test the service from Swagger.

And then click “Execute”.

And now we can actually see our real results returned from our Vehicles API Get service albeit it’s still our mocked data. And it even gives the Request URL of the service as well as the curl command to use to test from a command line.

I actually prefer testing my APIs as I develop them using Postman. But it’s nice to know about Swagger as one of our options and definitely about it’s documentation generating abilities.
Code Review
Let’s take a moment before moving on to do a quick code review of our baby Web Service and do a little introspective of some of the domain model decision choices we’ve made so far.
Revisit the Vehicle class
The Vehicle Entity class uses the same properties we thought of as vehicle attributes way back in chapter one.
For the Status property I use a C# enum with the values New or Used. I doubt the status of a vehicle will ever have any other value so it’s not worth breaking out that property to its own class or database table. But we do strongly type it as an enum rather than just use the string values of “New” and “Used”. This way we can avoid any stupid human typing errors and get to use intellisense as we are typing to select the correct value.

The VehicleType property in the Vehicle Entity class should be able to hold one of the values of “Car”, Truck”, or “Jeep”. But I can see the possibility of another value being added in the future. However, we don’t want to use an enum here because then if a user wanted to add a new type of vehicle, they would have to ask a developer to add it in, then it would have to be recompiled and deployed. So the user would have to wait until the next release to use the new type of vehicle. For that reason, we create a separate class called VehicleType with a Name property. The VehicleType.Name property will hold the value of either, “Car”, “Truck”, or “Jeep”.
Meanwhile, back in the Vehicle Entity class, we access a VehicleType with these two properties:
public int VehicleTypeId { get; set; }
public VehicleType VehicleType { get; set; } = null!;
Once we get to using Entity Framework Core to create the database and access data from within our code, we’ll see that the VehicleType property is a navigation property and will hold a VehicleType object as its value. The VehicleTypeId property is a foreign key used to locate the specific VehicleType object in the database to fill the VehicleType property.
Revisit the VehiclesController class
At the top of the HTTP Get method, we declare a variable called VehicleTypes and fill it with three newly instantiated VehicleType objects.
[HttpGet]
public IEnumerable<Vehicle> GetVehicles()
{
var vehicleTypes = new List<VehicleType>()
{
new VehicleType { Id = 1, Name = "Car" },
new VehicleType { Id = 2, Name = "Truck" },
new VehicleType { Id = 3, Name = "Jeep" }
};
Next we declare a variable called vehicles and manually fill it with Vehicle objects where we are able to select a Status value using intellisense and fill the VehicleType navigation property with one of the objects from the vehicleTypes variable.
var vehicles = new List<Vehicle>()
{
// Cars
new Vehicle {
Id = 1,
Status = Status.New,
Year = "2021",
Make = "Dodge",
Model = "Challenger",
Color = "Frostbite",
Price = 64164,
VIN = "2C3CDZFJ8MH631199",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
},
new Vehicle {
Id = 2,
Status = Status.Used,
Year = "2020",
Make = "Ford",
Model = "Escape",
Color = "Oxford White",
Price = 22999,
VIN = "1FMCU0F63LUC25826",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
},
new Vehicle {
Id = 3,
Status = Status.New,
Year = "2021",
Make = "Dodge",
Model = "Durange",
Color = "Black",
Price = 50557,
VIN = "1C4RDJDG5MC837730",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
},
Finally, we just return the list of vehicles we have built up for our mock data and .Net converts the results into JSON format for us. Easy Peasy!
Improve the JSON Results
If we take a closer look at our JSON Results, each status property in our vehicle results is an integer value of either 0 or 1 instead of a string value of “New” or “Used”. We prefer the later but, the default is to return the index of the enum position rather then its value. This is easily fixed however so let’s do that right now. Open up program.cs in the root of the FredsCarsAPI project and modify the code for the AddControllers
statement as shown below.
// ...
builder.Services.AddControllers()
.AddJsonOptions(x =>
{
x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
// ...
Adding in the JsonStringEnumConverter to the JSON serialization options as shown above should do the trick. Let’s run a Swagger test again and see the new results.

Yes! That is exactly what we want. Each status property in the vehicle results is now either “New” or “Used” rather than 0 or 1.
Another problem that pops out in the JSON results is the vehicleTypeID and vehicleType properties. We will eventually need VehicleTypeId in the back-end C# entity class to act as a foriegn key to fill the VehicleType property with a C# VehicleType object instance value. But we don’t need vehcileTypeId in our JSON results because the front end has no need for it.
Also we don’t need the whole C# VehicleType object on the front end. We just want to know what type of vehicle each result is: Car, Truck, or Jeep. Let’s see if we can tweak these two little nusainces so we can more easily consume the data from the front-end.
Create a DTO (Data Transfer Object)
In our existing Vehicles HTTP Get method we are currently returning a strongly typed IEnumerable of Vehicle or a IEnumerable<Vehicle>
. We do this because it’s always easier to work with strongly typed data then say a collection of anonymous objects. Because the Vehicle class has a VehicleType property (of type VehicleType) which itself is an object with two properties (Id and Name), it just doesn’t fit our front-end needs when converted to JSON. As already stated all we want is the Name of the VehicleType. Not the whole object.
To fix this we are going to create a VehilceDTO object. DTOs (Data Transfer Object)s are sometimes used when the strongly typed object(s) you are working with don’t exactly map to the client-side domain objects. DTOs are also used for security purposes for instance if a back-end C# object contains a password from a user table in a database and we don’t want that property to be sent to the front-end in JSON results.
Create a new folder called DTOs in the FredsAPI/Models folder. In the new DTOs folder create a C# class named VehicleDTO with the following code.
namespace FredsCarsAPI.Models.DTOs
{
public class VehicleDTO
{
public int Id { get; set; }
public Status Status { get; set; }
public string Year { get; set; } = string.Empty;
public string Make { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
public string Color { get; set; } = string.Empty;
public double Price { get; set; }
public string VIN { get; set; } = string.Empty;
public string VehicleType { get; set; } = null!;
}
}
This is basically the same code as our Vehicle class except instead of these two properties at the end which hold the VehicleType foriegn key and the VehicleType object properties:
public int VehicleTypeId { get; set; }
public VehicleType VehicleType { get; set; } = null!;
with just have a string property which will hold the name of the VehicleType:
public string VehicleType { get; set; } = null!;
Next make the following modifications to VehiclesController.cs in FredsCarsAPI/Controllers with the modifications highlighted in bold blue font.
using FredsCarsAPI.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace FredsCarsAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class VehiclesController : ControllerBase
{
[HttpGet]
public IEnumerable<VehicleDTO> GetVehicles()
{
var vehicleTypes = new List<VehicleType>
{
new VehicleType { Id = 1, Name = "Car" },
new VehicleType { Id = 2, Name = "Truck" },
new VehicleType { Id = 3, Name = "Jeep" }
};
var vehicles = new List<VehicleDTO>
{
// Cars
ConvertVehicleToDTO(
new Vehicle {
Id = 1,
Status = Status.New,
Year = "2021",
Make = "Dodge",
Model = "Challenger",
Color = "Frostbite",
Price = 64164,
VIN = "2C3CDZFJ8MH631199",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 2,
Status = Status.Used,
Year = "2020",
Make = "Ford",
Model = "Escape",
Color = "Oxford White",
Price = 22999,
VIN = "1FMCU0F63LUC25826",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 3,
Status = Status.New,
Year = "2021",
Make = "Dodge",
Model = "Durange",
Color = "Black",
Price = 50557,
VIN = "1C4RDJDG5MC837730",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 4,
Status = Status.New,
Year = "2021",
Make = "Nissan",
Model = "Niro",
Color = "Blue",
Price = 24960,
VIN = "2XYZT67JTF24AZG856",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 5,
Status = Status.New,
Year = "2021",
Make = "Kia",
Model = "Stinger",
Color = "Gray",
Price = 36090,
VIN = "6FG146B89624AZ7952",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 6,
Status = Status.New,
Year = "2021",
Make = "Kia",
Model = "Stinger",
Color = "Gray",
Price = 36090,
VIN = "6FG146B89624AZ7952",
VehicleTypeId = 1,
VehicleType = vehicleTypes.Find(v => v.Id == 1)
}
),
// Trucks
ConvertVehicleToDTO(
new Vehicle {
Id = 7,
Status = Status.New,
Year = "2022",
Make = "Ram",
Model = "Crew Cab",
Color = "Black",
Price = 68400,
VIN = "3C6UR5DL8NG157035",
VehicleTypeId = 2,
VehicleType = vehicleTypes.Find(v => v.Id == 2)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 8,
Status = Status.Used,
Year = "2017",
Make = "Ram",
Model = "Crew Cab",
Color = "Red",
Price = 33000,
VIN = "1C6RR7PT0HS814596",
VehicleTypeId = 2,
VehicleType = vehicleTypes.Find(v => v.Id == 2)
}
),
// Jeeps
ConvertVehicleToDTO(
new Vehicle {
Id = 9,
Status = Status.New,
Year = "2022",
Make = "Jeep",
Model = "Compass",
Color = "White",
Price = 34980,
VIN = "3C4NJDFB5NT114024",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 10,
Status = Status.New,
Year = "2022",
Make = "Jeep",
Model = "Compass",
Color = "Red",
Price = 39275,
VIN = "3C4NJDCB1NT118172",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 11,
Status = Status.New,
Year = "2022",
Make = "Jeep",
Model = "Grand Cherokee",
Color = "Pearlcoat",
Price = 53575,
VIN = "1C4RJKBG5M8201121",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)
}
),
ConvertVehicleToDTO(
new Vehicle {
Id = 12,
Status = Status.New,
Year = "2021",
Make = "Jeep",
Model = "Wrangler Sport S",
Color = "Green",
Price = 40940,
VIN = "1C4GJXAN0MW856433",
VehicleTypeId = 3,
VehicleType = vehicleTypes.Find(v => v.Id == 3)
}
)
};
return vehicles;
}
private VehicleDTO ConvertVehicleToDTO(Vehicle vehcile)
{
return new VehicleDTO
{
Id = vehcile.Id,
Status = vehcile.Status,
Year = vehcile.Year,
Make = vehcile.Make,
Model = vehcile.Model,
Color = vehcile.Color,
Price = vehcile.Price,
VIN = vehcile.VIN,
VehicleType = vehicle.VehicleType.Name
};
}
}
}
In the code above we are now returning an IEnumerable<VehicleDTO>
instead of an IEnumerable<Vehicle>
.
At the bottom of the VehiclesController class we created a private helper method called ConvertVehicleToDTO to convert Vehicle objects to VehicleDTO objects.
Once the converter helper is in place all we have to do in the HTTP Get method is convert each Vehcile object we’ve already built up into a VehicleDTO which won’t contain the unwanted properties discussed above but will have the VehicleType name.
Let’s run the Get method one more time in Swagger and look at our results.

And that’s perfect. We got rid of the extraneous VehcileType information and now just send the VehicleType Name.
At this point it should be ok to delete the WeatherForecastController.cs and WeatherForecast.cs files.

What’s Next
Now that we have some data to work with, in the next module we will create an Angular Component to consume it.