Back to: Microservices using ASP.NET Core Tutorials
Creating Microservices for Vehicles
In this article, we’re going to create microservices for vehicles. Please read our previous article discussing the Project Setup for Microservices using ASP.NET Core Web API. Let me tell you the basic flow of this vehicle microservice, this vehicle microservice will be based on five different methods.
- GET – GetVehicles(); It will return the list of vehicles.
- GET – GetVehicleById(int id); It will return the specific vehicle detail according to the vehicle ID.
- POST – AddVehicle(Vehicle vehicle); It will be used to add the vehicle record.
- PUT – UpdateVehicle(int id, Vehicle vehicle); It will used to update the vehicle record.
- DELETE – DeleteVehicle(int id); It will be used to delete the vehicle record.
Create Models for Vehicle Service
Before creating the model class for vehicle service, first, Delete the below-highlighted file from VehiclesAPI, CustomersAPI, and ReservationsAPI project.
First, create a folder with the name Models inside the VehiclesAPI microservice project. This is the folder where we are going to create all the Models required for the Vehicles microservice. Right-click on this Models folder, then add a class file with the name Vehicle.cs, and then copy and paste the following code into it. This class contains the properties required for a Vehicle.
namespace VehiclesAPI.Models { public class Vehicle { public int Id { get; set; } public string? Name { get; set; } public double Price { get; set; } public string? ImageUrl { get; set; } public string? Displacement { get; set; } public string? MaxSpeed { get; set; } public double Length { get; set; } public double Width { get; set; } public double Height { get; set; } } }
DbContext for Vehicle Service
Next, we are going to create the DB Context class. The DB context class is an important class. It acts as a bridge between our model class and our database and it’s also responsible for converting our C# Statement (LINQ Queries) into SQL queries and sending them to the database for execution.
What I mean is when we perform the CRUD operations with the database, then will use LINQ queries, and the DbContext object will convert those LINQ queries into SQL queries and send them to the database for execution.
According to MSDN, an instance of DbContext represents a session with the database and can be used to query and save instances of your entities. DbContext is a combination of the Unit of Work and Repository patterns.
The DbContext class is an integral part of the Entity Framework. The DBContext Class in Entity Framework Core is used by our application to interact with the underlying database. That means this class manages the database connection and performs CRUD Operations with the underlying database. For read the following article to learn more about the DbContext Class in Entity Framework Core.
https://dotnettutorials.net/lesson/dbcontext-entity-framework-core/
Creating Context Class
Let us first create a folder and then rename the folder as Data and then create a class file with the name ApiDbContext.cs inside this Data folder and then copy and paste the following code into it.
using Microsoft.EntityFrameworkCore; using VehiclesAPI.Models; namespace VehiclesAPI.Data { public class ApiDbContext : DbContext { //OnConfiguring() method is used to select and configure the data source protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { //use this to configure the context object //Configuring the Connection String optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=VehiclesAPIDB;Trusted_Connection=True;TrustServerCertificate=True;"); } public DbSet<Vehicle> Vehicles { get; set; } } }
As you can see, this class is derived from DbContext and DbContext comes under Microsoft.EntityFrameworkCore namespace. Inside this ApiDbContext class, we add one property of DbSet of Vehicle type. And here, we named the property as Vehicles. So, in this case, the entity framework core will create a table inside the database with the same name which is Vehicles.
Within the OnConfiguring method, we provide the connection string to the DB context class. The UseSqlServer server, method will take the connection string. Add the name of the SQL Server and provide a user-friendly name for the database.
Migrations in VehiclesAPI Service
We have set up the connection string and now in order to create a database, we need to add the migrations. To enable the migrations first will need to install a package that is Microsoft.EntityFrameworkCore. Tools and we have already installed this package.
Entity Framework Core Includes different migration commands to create or update the database based on the model. At this point, there is no EFCoreDB1 database in SQL Server. So, we need to create the database from the model (Entities and Context) by adding a migration.
We can execute the migration command using the NuGet Package Manager Console as well as using the dotnet CLI (command line interface) command.
In Visual Studio, open the NuGet Package Manager Console. To launch Package Manager Console, select Tools => NuGet Package Manager => Package Manager Console from the menu as shown in the image below.
This will open the following Package Manager Console.
Before doing Migrations, you need to select the project in which you are adding the migrations. For example, if you are adding the migration in VehiclesAPI microservice, then select the VehiclesAPI project, and in the package manager console, set the default project to VehiclesAPI microservice.
Similarly, when we look at the project migrations in some other project, then we need to change that default project. At this time, we want to add the migrations in the VehiclesAPI microservice project, so make sure the VehiclesAPI project is selected.
Now type the add-migration VehiclesAPIDB1 command, select the project where your Context class is, and press the enter button, as shown in the image below. This will generate the migration script.
Once the above code is executed successfully, it will create a new folder named Migrations in the VehiclesAPI project and create the following two Migrations files, as shown below.
The script will be used to add the database and tables, but we have not actually created the database yet. So, after creating a migration, don’t think that the database is created. We still need to create the database using the update-database command in the Package Manager Console as below.
Once the command is executed successfully, it will create the database with the name and location specified in the connection string in the UseSqlServer() method. It creates a table for each DbSet property (Vehicles). Now, you can verify the same in SQL Server as shown below using SSMS.
Create an Interface for Vehicle Service
Next, we are going to start or work with the interfaces. We will use the repository pattern and interfaces. So, first, add a folder with the name Interfaces within the VehiclesAPI Project root directory, and inside this folder add an interface with the name IVehicle.cs and then copy and paste the following code. Inside this interface, we have provided the method signature to perform simple operations like get all vehicles, get vehicle by ID, add vehicle, update vehicle, and delete vehicle.
using VehiclesAPI.Models; namespace VehiclesAPI.Interfaces { public interface IVehicle { // Return list of Vehicles Task<List<Vehicle>> GetAllVehicles(); // Return single vehicle data against the vehicle id // This method will also take an ID parameter Task<Vehicle> GetVehicleById(int id); // This method will add the vehicle /* This method will take vehicle object as a parameter and will not return anything.*/ Task AddVehicle(Vehicle vehicle); // This method will update the vehicle data /* We need to pass the id as a parameter of type integer to update the vehicle record and will not return anything. */ Task UpdateVehicle(int id, Vehicle vehicle); // This method used to delete a particular record based on id as a parameter Task DeleteVehicle(int id); } }
Create Vehicle Service
We are going to work with the services basically in the IVehicle interface. We have defined these methods and now look at a vehicle service that will add the IVehicle methods implementation. So, first, add a new folder with the name Services within the VehiclesAPI Project and inside this Services folder. add a new class file with the name VehicleService.cs and then copy and paste the following code into it.
using VehiclesAPI.Data; using VehiclesAPI.Interfaces; using VehiclesAPI.Models; using Microsoft.EntityFrameworkCore; namespace VehiclesAPI.Services { public class VehicleService : IVehicle { private ApiDbContext _context; public VehicleService() { _context = new ApiDbContext(); } public async Task AddVehicle(Vehicle vehicle) { // This line will add vehicle data and set the database. await _context.Vehicles.AddAsync(vehicle); await _context.SaveChangesAsync(); } public async Task DeleteVehicle(int id) { var vehicle = await _context.Vehicles.FindAsync(id); if (vehicle != null) { _context.Vehicles.Remove(vehicle); await _context.SaveChangesAsync(true); } } public async Task<List<Vehicle>> GetAllVehicles() { // This line will return list of vehicles var vehicles = await _context.Vehicles.ToListAsync(); return vehicles; } public async Task<Vehicle> GetVehicleById(int id) { // This line will return the specific vehicle record based on id pass as a parameter var vehicle = await _context.Vehicles.FindAsync(id); return vehicle; } public async Task UpdateVehicle(int id, Vehicle vehicle) { var vehicleObj = await _context.Vehicles.FindAsync(id); vehicleObj.Name = vehicle.Name; vehicleObj.ImageUrl = vehicle.ImageUrl; vehicleObj.Height = vehicle.Height; vehicleObj.Width = vehicle.Width; vehicleObj.MaxSpeed = vehicle.MaxSpeed; vehicleObj.Price = vehicle.Price; vehicleObj.Displacement = vehicle.Displacement; await _context.SaveChangesAsync(); } } }
As you can see in the above code, inside the vehicle service we provided the implementation of methods that we have written in the IVehicle interface. To access the DbSet property will add a field of type, ApiDbContext, and then add a constructor. Then we create a new instance of ApiDbContext and assign it to the context. Now, with the DB Context, we access the Vehicles property which we have defined in the ApiDbContext class. Here, we have used async and await keywords for asynchronous calls.
Extension Methods and IOC in Vehicle Service
We are going to work with the dependency injection inside the dot net core project. Dependency injection is a design pattern that makes a class independent of its dependencies. With dependency injection, we don’t rely on the concrete implementation of a class instead we rely on the interfaces. This makes our code more maintainable and almost in every enterprise project dependency injection pattern is used heavily.
Let’s see how we can use this in our application. So, we have an interface, i.e., IVehicle, and the corresponding service class, i.e., VehicleService.
Now, suppose, we want to consume the methods of VehicleService class, then we need to create an instance of the VehicleService class. Suppose, we want to consume the VehicleService class inside a controller class, then we need to create an instance of the VehicleService class inside that controller.
Now, instead of creating the VehicleService instance inside the Controller class, we would like to inject the VehicleService instance to the controller class using dependency injection or IOC or Inversion of Container which will take the responsibility to create the instance and inject the instance to the controller class.
Basically, within the IOC container, we need to register the IVehicle service interface and VehicleService class and it’s the IOC container that will resolve the dependencies for us.
Now, with this dependency injection in place, we don’t need to create an object of VehicleService for accessing the methods of the VehicleService class. We just need to pass the IVehicle interface in the constructor and with the help of this interface, we can access the methods easily. By default, ASP.NET Core comes with a built-in IOC container, so we just need to use it. So, open the Program.cs file and write the below code.
builder.Services.AddScoped<IVehicle, VehicleService>();
Here, we use the AddScoped method to register the vehicle interface and the vehicle service class. Now, it’s the responsibility of this scope, will create a new instance of vehicle service class. So, with this change, your Program class should look as follows.
using VehiclesAPI.Interfaces; using VehiclesAPI.Services; namespace VehiclesAPI { public class Program { public static void Main(string[] args) { 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(); builder.Services.AddScoped<IVehicle, VehicleService>(); 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(); } } }
Controllers and Actions for Vehicle Service
Now we’ll add a controller and inject the interface into the constructor of the controller. So, go to the Controllers folder and add a new controller class with the name VehiclesController. Make sure you have selected the API option and just pick the project template with read-write actions and click on the Add button as shown in the below image. This template will only contain some code, and we just need to modify this.
Next, provide the Controller name as VehiclesController and click on the Add button as shown in the below image.
Once you click on the Add button, then it will create the VehiclesController. Once you created the Vehicles controller, and copy paste the following code into it. Here, as you can see, we have created a field of type IVehicle interface, added a constructor, and then injected the IVehicle interface inside the constructor. We have also implemented the functionality of the controller class and all action methods.
using Microsoft.AspNetCore.Mvc; using VehiclesAPI.Interfaces; using VehiclesAPI.Models; namespace VehiclesAPI.Controllers { [Route("api/[controller]")] [ApiController] public class VehiclesController : ControllerBase { private IVehicle _vehicleService; public VehiclesController(IVehicle vehicleService) { _vehicleService = vehicleService; } // GET: api/<VehiclesController> [HttpGet] public async Task<IEnumerable<Vehicle>> Get() { var vehicles = await _vehicleService.GetAllVehicles(); return vehicles; } // GET api/<VehiclesController>/5 [HttpGet("{id}")] public async Task<Vehicle> Get(int id) { return await _vehicleService.GetVehicleById(id); } // POST api/<VehiclesController> [HttpPost] public async Task Post([FromBody] Vehicle vehicle) { await _vehicleService.AddVehicle(vehicle); } // PUT api/<VehiclesController>/5 [HttpPut("{id}")] public async Task Put(int id, [FromBody] Vehicle vehicle) { await _vehicleService.UpdateVehicle(id, vehicle); } // DELETE api/<VehiclesController>/5 [HttpDelete("{id}")] public async Task Delete(int id) { await _vehicleService.DeleteVehicle(id); } } }
With these changes, your VehiclesAPI should look as shown below.
Run VehiclesAPI Service Project
Now, we will run our project and test the Vehicles Microservice. So, let’s quickly run this project inside the web browser.
At this moment, the table inside the database is empty, so first we’ll go to the post request and insert the data.
POST Request:
Response:
Table:
GET Request:
GET Response:
Note: In the same way, you can test other HTTP Verbs.
Registration Open For New Online Training
Enhance Your Professional Journey with Our Upcoming Live Session. For complete information on Registration, Course Details, Syllabus, and to get the Zoom Credentials to attend the free live Demo Sessions, please click on the below links.
what’s about others Microservices?
Hello, Please create other microservices and Gateway API and communication between each microservices.
Hi, it would be good even if you provided other microservices and Gateway API and communication between each microservices.