Microservices Implementation With Ocelot Gateway Using .NET Core 6 API And Angular 14

In this article, we are going to create two microservices using Ocelot API Gateway using Client Application, which is designed in Angular 14.

Agenda

  • Introduction of Microservice
  • Introduction of Ocelot API Gateway
  • Step-by-step implementation of microservices
  • Implementation of Ocelot API Gateway
  • Client Application using Angular 14

Prerequisites:

  • Understanding of .NET Core API, C#, and Angular
  • Visual Studio 2022
  • VS Code
  • Node Js
  • Angular 14
  • .NET Core 6 SDK

Introduction of Microservice

There are two types of architecture for design applications: the first is monolithic, and the second one is microservices.

1. Monolithic Architecture

  • In a Monolithic Application, all components are tightly coupled to each other and run using a single process.
  • It’s very difficult to make some changes in the future when monolithic architecture is used, because the components of the application will be tightly coupled to each other. When trying to modify or introduce new things into the existing component, this may impact all applications.
  • Suppose we have an E-commerce application and in that application, we used multiple components, like Login, Posts, and News Feed. In that case, when we introduce or change something in one of the components, it will impact the application because the application is tightly coupled and interconnected to each other using a single service.
  • If we have deployed this type of application on the cloud, and in the future we need to add something into the Posts Component, then we will be required to stop the whole application. This will impact performance and delivery services' efficiency. Also, it’s difficult to manage.

Microservice Architecture

2. Microservice Architecture

  • In the Microservice Architecture, we create application components that will work independently, without being tightly coupled to each other, in their own environments.
  • Also, we can easily communicate with each other with the help of API Gateways and other such programs.
  • So, basically, when we use microservices, they will run their own environment, and they will not impact one another when we change something in one of the services.
  • Also, this is easy to manage while the application is in a development phase. Each developer will work independently on each service, and because of that, it is easy to manage and integrate components.

Introduction of Ocelot API Gateway

  • Ocelot is the API Gateway for the .NET Platform and which is work as the entry point of our application when we use microservice architecture.
  • The following diagram is from Microsoft Technical Documentation.

Ocelot API Gateway

  • API gateway is present between the client and microservices and acts as middleware for communication between different microservices as shown in the above diagram.

Step-by-step implementation of microservices

Let’s start.

Step 1

Create a Blank Empty solution using a visual studio.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 2

Configure your project.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 3

Project Structure:

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 4

Create a new folder inside the solution and name it Microservices. Next, create ProductAPI and UserAPI projects inside that.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 5

Configure ProductAPI project.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 6

Provide additional information related to project.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 7

Next, create the UserAPI project inside the Microservices folder and follow the same steps as we used to create ProductAPI.

Step 8

Create an Ocelot API Gateway project outside the Microservices folder.

Let’s start the implementation of ProductAPI

Project Structure

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 1

 Install the following NuGet packages.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 2

Create Product Class inside the Model folder.

namespace ProductAPI.Models
{
    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public string ProductDescription { get; set; }
        public int ProductPrice { get; set; }
        public int ProductStock { get; set; }
    }
}

Step 3

Next, Create DBContextClass inside the Data folder.

using Microsoft.EntityFrameworkCore;
using ProductAPI.Models;

namespace ProductAPI.Data
{
    public class DbContextClass : DbContext
    {
        protected readonly IConfiguration Configuration;

        public DbContextClass(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        }

        public DbSet<Product> Products { get; set; }
    }
}

Step 4

After that, create IProductService and ProductService inside the services folder.

IProductService

using ProductAPI.Models;

namespace ProductAPI.Services
{
    public interface IProductService
    {
        public IEnumerable<Product> GetProductList();
        public Product GetProductById(int id);
        public Product AddProduct(Product product);
        public Product UpdateProduct(Product product);
        public bool DeleteProduct(int Id);
    }
}

ProductService

using ProductAPI.Data;
using ProductAPI.Models;

namespace ProductAPI.Services
{
    public class ProductService : IProductService
    {
        private readonly DbContextClass _dbContext;

        public ProductService(DbContextClass dbContext)
        {
            _dbContext = dbContext;
        }
        public IEnumerable<Product> GetProductList()
        {
            return _dbContext.Products.ToList();
        }
        public Product GetProductById(int id)
        {
            return _dbContext.Products.Where(x => x.ProductId == id).FirstOrDefault();
        }

        public Product AddProduct(Product product)
        {
            var result = _dbContext.Products.Add(product);
            _dbContext.SaveChanges();
            return result.Entity;
        }

        public Product UpdateProduct(Product product)
        {
            var result = _dbContext.Products.Update(product);
            _dbContext.SaveChanges();
            return result.Entity;
        }
        public bool DeleteProduct(int Id)
        {
            var filteredData = _dbContext.Products.Where(x => x.ProductId == Id).FirstOrDefault();
            var result = _dbContext.Remove(filteredData);
            _dbContext.SaveChanges();
            return result != null ? true : false;
        }
    }
}

Step 5

Configure the connection string inside the appsetting.json file.

(Note: I used the same database for demo purposes in both Product and User Microservice but in a real-time scenario you can use the separate database for each microservice as per microservice guidelines and protocols.)

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=DESKTOP;Initial Catalog=OcelotGatewayDemo;User Id=sa;Password=*****;"
  }
}

Step 6

Later on, configure a few services inside Program.cs class.

using ProductAPI.Data;
using ProductAPI.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddScoped < IProductService, ProductService > ();
builder.Services.AddDbContext < DbContextClass > ();
builder.Services.AddControllers();
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();

Step 7

Next, Create a ProductController.cs.

using Microsoft.AspNetCore.Mvc;
using ProductAPI.Models;
using ProductAPI.Services;
namespace ProductAPI.Controllers {
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController: ControllerBase {
        private readonly IProductService productService;
        public ProductController(IProductService _productService) {
                productService = _productService;
            }
            [HttpGet]
        public IEnumerable < Product > ProductList() {
                var productList = productService.GetProductList();
                return productList;
            }
            [HttpGet("{id}")]
        public Product GetProductById(int id) {
                return productService.GetProductById(id);
            }
            [HttpPost]
        public Product AddProduct(Product product) {
                return productService.AddProduct(product);
            }
            [HttpPut]
        public Product UpdateProduct(Product product) {
                return productService.UpdateProduct(product);
            }
            [HttpDelete("{id}")]
        public bool DeleteProduct(int id) {
            return productService.DeleteProduct(id);
        }
    }
}

Step 8

Finally, execute the following command in the package manager console to create migration and create the database.

add-migration "Initial"
update-database

Implementation of UserAPI service

Project Structure:

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 1

 Install the following NuGet packages:

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 2

Create a User Class inside the Model folder.

namespace UserAPI.Models
{
    public class User
    {
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Address { get; set; }
    }
}

Step 3

Next, Create DBContextClass inside the Data folder.

using Microsoft.EntityFrameworkCore;
using UserAPI.Models;

namespace UserAPI.Data
{
    public class DbContextClass : DbContext
    {
        protected readonly IConfiguration Configuration;

        public DbContextClass(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        }

        public DbSet<User> Users { get; set; }
    }
}

Step 4

After that, create IUserService and UserService inside the services folder.

IUserService

using UserAPI.Models;

namespace UserAPI.Services
{
    public interface IUserService
    {
        public IEnumerable<User> GetUserList();
        public User GetUserById(int id);
        public User AddUser(User product);
        public User UpdateUser(User product);
        public bool DeleteUser(int Id);
    }
}

UserService

using UserAPI.Data;
using UserAPI.Models;

namespace UserAPI.Services
{
    public class UserService : IUserService
    {
        private readonly DbContextClass _dbContext;

        public UserService(DbContextClass dbContext)
        {
            _dbContext = dbContext;
        }

        public User AddUser(User product)
        {
            var result = _dbContext.Users.Add(product);
            _dbContext.SaveChanges();
            return result.Entity;
        }

        public bool DeleteUser(int Id)
        {
            var filteredData = _dbContext.Users.Where(x => x.UserId == Id).FirstOrDefault();
            var result = _dbContext.Remove(filteredData);
            _dbContext.SaveChanges();
            return result != null ? true : false;
        }

        public User GetUserById(int id)
        {
            return _dbContext.Users.Where(x => x.UserId == id).FirstOrDefault();
        }

        public IEnumerable<User> GetUserList()
        {
            return _dbContext.Users.ToList();
        }

        public User UpdateUser(User product)
        {
            var result = _dbContext.Users.Update(product);
            _dbContext.SaveChanges();
            return result.Entity;
        }
    }
}

Step 5

Configure the connection string inside the appsetting.json file.

(Note: I used the same database for demo purposes in both Product and User Microservice but in a real-time scenario you can use the separate database for each microservice as per microservice guidelines and protocols.)

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=DESKTOP;Initial Catalog=OcelotGatewayDemo;User Id=sa;Password=**@1;"
  }
}

Step 6

Later on, configure a few services inside Program.cs class.

using UserAPI.Data;
using UserAPI.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddScoped < IUserService, UserService > ();
builder.Services.AddDbContext < DbContextClass > ();
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();

Step 7

Next, Create a UserController.cs.

using Microsoft.AspNetCore.Mvc;
using UserAPI.Models;
using UserAPI.Services;
namespace UserAPI.Controllers {
    [Route("api/[controller]")]
    [ApiController]
    public class UserController: ControllerBase {
        private readonly IUserService userService;
        public UserController(IUserService _userService) {
                userService = _userService;
            }
            [HttpGet]
        public IEnumerable < User > UserList() {
                var userList = userService.GetUserList();
                return userList;
            }
            [HttpGet("{id}")]
        public User GetUserById(int Id) {
                return userService.GetUserById(Id);
            }
            [HttpPost]
        public User AddUser(User user) {
                return userService.AddUser(user);
            }
            [HttpPut]
        public User UpdateUser(User user) {
                return userService.UpdateUser(user);
            }
            [HttpDelete("{id}")]
        public bool DeleteUser(int id) {
            return userService.DeleteUser(id);
        }
    }
}

Step 8

Finally, execute the following command in the package manager console to create migration, and create the database.

add-migration "Initial"
update-database

Implementation of Ocelot API Gateway

Step 1

Install Ocelot NuGet Package.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 2

Project Structure:

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 3

Create an ocelot.json file for routing.

{
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:7283"
  },
  "Routes": [
    {
      "UpstreamPathTemplate": "/gateway/product",
      "UpstreamHttpMethod": [ "Get" ],
      "DownstreamPathTemplate": "/api/product",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7233
        }
      ]
    },
    {
      "UpstreamPathTemplate": "/gateway/product/{id}",
      "UpstreamHttpMethod": [ "Get", "Delete" ],
      "DownstreamPathTemplate": "/api/product/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7233
        }
      ]
    },
    {
      "UpstreamPathTemplate": "/gateway/product",
      "UpstreamHttpMethod": [ "Post", "Put" ],
      "DownstreamPathTemplate": "/api/product",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7233
        }
      ]
    },
    {
      "UpstreamPathTemplate": "/gateway/user",
      "UpstreamHttpMethod": [ "Get" ],
      "DownstreamPathTemplate": "/api/user",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7285
        }
      ]
    },
    {
      "UpstreamPathTemplate": "/gateway/user/{id}",
      "UpstreamHttpMethod": [ "Get", "Delete" ],
      "DownstreamPathTemplate": "/api/user/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7285
        }
      ]
    },
    {
      "UpstreamPathTemplate": "/gateway/user",
      "UpstreamHttpMethod": [ "Post", "Put" ],
      "DownstreamPathTemplate": "/api/user",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 7285
        }
      ]
    }
  ]
}
  • The Ocelot file has two sections: one is Global Configuration, which acts as an entry point of our application; and the other is Routes, which is used to define routes of our microservices.
  • UpstreamPathTemplate is used to receive client requests and redirects them to the particular microservice.
  • UpstreamHttpMethod is used to define HTTP attributes, which helps to the gateway to getting the type of request.
  • DownstreamTemplatePath is the microservice endpoint that takes the request from UpstreamPathTemplate.
  • DownstreamScheme defines the scheme of a request.
  • DownstreamHostAndPorts defines the hostname and port number of microservices that are present inside the lauchSetting.json file.

Step 4

Configure the ocelot.json file inside Program.cs class and register services related to that. Then, apply CORS policy for client communication, which we are going to create using Angular.

using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddCors(options => {
    options.AddPolicy("CORSPolicy", builder => builder.AllowAnyMethod().AllowAnyHeader().AllowCredentials().SetIsOriginAllowed((hosts) => true));
});
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
builder.Services.AddOcelot(builder.Configuration);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseCors("CORSPolicy");
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
await app.UseOcelot();
app.Run();

Step 5

Right-click on the solution and open the property. Then, apply to start on all three projects that we have created.

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Step 6

Run the project.

This is all about backend application using microservices, let’s start the client application.

Client Application using Angular 14

Step 1

Create a new angular project.

ng new ClientApplication

Step 2

We use bootstrap in this application. So, use the following command to install bootstrap.

npm install bootstrap

Next, add the bootstrap script inside the angular.json file inside the scripts and styles section.

"styles": [
             "src/styles.css",
             "./node_modules/bootstrap/dist/css/bootstrap.min.css"
           ],
           "scripts": [
             "./node_modules/bootstrap/dist/js/bootstrap.min.js"
           ]

Step 3

Install Toaster module for pop-up and notification.

npm install ngx-toastr –save

Then, add the toaster in the styles section inside the angular.json file.

"styles": [
             "src/styles.css",
             "node_modules/ngx-toastr/toastr.css",
             "./node_modules/bootstrap/dist/css/bootstrap.min.css"
           ],
           "scripts": [
             "./node_modules/bootstrap/dist/js/bootstrap.min.js"
           ]

Step 4

Create Product and User class inside the Model folder.

Product.ts

export class Product {
    productId: any;
    productName?: string;
    productPrice?: number;
    productDescription?: string;
    productStock?: number;
  }

User.ts

export class User {
    userId: any;
    userName?: string;
    address?: string;
  }

Step 5

Next, create three components using the following command:

ng g c homepage

ng g c products

ng g c users

Step 6

After that, create a Product angular service.

ng g s products
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Product } from '../Models/Product';
import configurl from '../../assets/config/config.json'
@Injectable({
  providedIn: 'root'
})
export class ProductsService {

  url = configurl.apiServer.url + '/product';
  constructor(private http: HttpClient) { }
  getProductList(): Observable<Product[]> {
    return this.http.get<Product[]>(this.url);
  }
  postProductData(productData: Product): Observable<Product> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.post<Product>(this.url, productData, httpHeaders);
  }
  updateProduct(product: Product): Observable<Product> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.put<Product>(this.url, product, httpHeaders);
  }
  deleteProductById(id: number): Observable<number> {
    return this.http.delete<number>(this.url + '/' + id);
  }
  getProductDetailsById(id: string): Observable<Product> {
    return this.http.get<Product>(this.url + '/' + id);
  }
}

Step 7

Next, create Users angular service.

ng g s users
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { User } from '../Models/User';
import configurl from '../../assets/config/config.json'
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class UsersService {

  url = configurl.apiServer.url + '/user';
  constructor(private http: HttpClient) { }
  getUserList(): Observable<User[]> {
    return this.http.get<User[]>(this.url);
  }
  postUserData(userData: User): Observable<User> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.post<User>(this.url, userData, httpHeaders);
  }
  updateUser(user: User): Observable<User> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.put<User>(this.url, user, httpHeaders);
  }
  deleteUserById(id: number): Observable<number> {
    return this.http.delete<number>(this.url + '/' + id);
  }
  getUserDetailsById(id: string): Observable<User> {
    return this.http.get<User>(this.url + '/' + id);
  }
}

Step 8

Create app-routing.module.ts to define the routes of the angular component.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomepageComponent } from './homepage/homepage.component';
import { ProductsComponent } from './products/products.component';
import { UsersComponent } from './users/users.component';

const routes: Routes = [
  { path: '', component: HomepageComponent },
  { path: 'products', component: ProductsComponent },
  { path: 'users', component: UsersComponent }
  
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Step 9

Configure and define all modules in the app.module.ts.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { ProductsComponent } from './products/products.component';
import { UsersComponent } from './users/users.component';
import { ToastrModule } from 'ngx-toastr';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HomepageComponent } from './homepage/homepage.component';

@NgModule({
  declarations: [
    AppComponent,
    ProductsComponent,
    UsersComponent,
    HomepageComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    ToastrModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    ToastrModule.forRoot(),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 10

Create a config folder inside the assets folder, and then create a config.json file to define the backend server API URL.

{
    "apiServer": {
      "url": "https://localhost:7283/gateway",
      "version": "v1"
    }
}

Step 11

App Component:

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  title = 'ProductWebAPP';
}

app.component.html

<router-outlet></router-outlet>

Homepage Component

homepage.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-homepage',
  templateUrl: './homepage.component.html',
  styleUrls: ['./homepage.component.css']
})
export class HomepageComponent {

  title: string ="Ocelot Gateway Microservices Demo";

}

homepage.component.html

<nav class="navbar navbar-expand-lg navbar navbar-dark bg-dark">
    <a class="navbar-brand" href="#">{{title}}</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item">
          <a class="nav-link" routerLink="/products">Products</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" routerLink="/users">Users</a>
          </li>
      </ul>
    </div>
  </nav>
  <h1>Welcome To Programming World!</h1>
  

Product Component

product.component.ts

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { ProductsService } from '../products/products.service';
import { Product } from '../Models/Product';
import { FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
@Component({
    selector: 'app-products',
    templateUrl: './products.component.html',
    styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
    ProductList ? : Observable < Product[] > ;
    ProductList1 ? : Observable < Product[] > ;
    productForm: any;
    productId = 0;
    constructor(private formbulider: FormBuilder, private productService: ProductsService, private router: Router, private toastr: ToastrService) {}
    ngOnInit() {
        this.productForm = this.formbulider.group({
            productName: ['', [Validators.required]],
            productPrice: ['', [Validators.required]],
            productDescription: ['', [Validators.required]],
            productStock: ['', [Validators.required]]
        });
        this.getProductList();
    }
    getProductList() {
        this.ProductList1 = this.productService.getProductList();
        this.ProductList = this.ProductList1;
    }
    PostProduct(product: Product) {
        const product_Master = this.productForm.value;
        this.productService.postProductData(product_Master).subscribe(
            () => {
                this.getProductList();
                this.productForm.reset();
                this.toastr.success('Data Saved Successfully');
            });
    }
    ProductDetailsToEdit(id: string) {
        this.productService.getProductDetailsById(id).subscribe(productResult => {
            this.productId = productResult.productId;
            this.productForm.controls['productName'].setValue(productResult.productName);
            this.productForm.controls['productPrice'].setValue(productResult.productPrice);
            this.productForm.controls['productDescription'].setValue(productResult.productDescription);
            this.productForm.controls['productStock'].setValue(productResult.productStock);
        });
    }
    UpdateProduct(product: Product) {
        product.productId = this.productId;
        const product_Master = this.productForm.value;
        this.productService.updateProduct(product_Master).subscribe(() => {
            this.toastr.success('Data Updated Successfully');
            this.productForm.reset();
            this.getProductList();
        });
    }
    DeleteProduct(id: number) {
        if (confirm('Do you want to delete this product?')) {
            this.productService.deleteProductById(id).subscribe(() => {
                this.toastr.success('Data Deleted Successfully');
                this.getProductList();
            });
        }
    }
    Clear(product: Product) {
        this.productForm.reset();
    }
}

prouct.component.html

<nav class="navbar navbar-expand-lg navbar navbar-dark bg-dark">
    <a class="navbar-brand" href="#">Product Application</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" routerLink="/">Home</a>
        </li>
        <li class="nav-item active">
          <a class="nav-link" routerLink="/products">Products</a>
        </li>
        <li class="nav-item active">
            <a class="nav-link" routerLink="/users">Users</a>
        </li>
      </ul>
    </div>
  </nav>
  
  <form class="form-horizontal" [formGroup]="productForm">
      <h1 style="text-align: center;">Welcome to Angular 14 CRUD with .NET 6 Web API</h1>
      <div>
      <div class="form-group">
        <label class="control-label col-sm-2" for="pwd">Product Name:</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="txtProductName" formControlName="productName"
            placeholder="Name of Product">
        </div>
      </div>
      <br />
      <div class="form-group">
        <label class="control-label col-sm-2" for="pwd">Product Description :</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="txtProductDescription" formControlName="productDescription"
            placeholder="Product Description">
        </div>
      </div>
      <br />
      <div class="form-group">
        <label class="control-label col-sm-2" for="pwd">Product Cost:</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="txtProductPrice" formControlName="productPrice" placeholder="Price of Product">
        </div>
      </div>
      <br />
      <div class="form-group">
        <label class="control-label col-sm-2" for="pwd">Product Stock Available :</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="txtStock" formControlName="productStock" placeholder="Stock Available">
        </div>
      </div>
      <br />
       <div class="form-group">
        <div class="container">
          <div class="row">
            <div class="col-sm">
              <button type="submit" class="btn btn-primary" (click)="PostProduct(productForm.value)">Submit</button> 
            </div>
            <div class="col-sm">
              <button type="submit" class="btn btn-primary" (click)="UpdateProduct(productForm.value)">Update</button>
            </div>
            <div class="col-sm">
              <button type="submit" class="btn btn-primary" (click)="Clear(productForm.value)">Clear</button>
            </div>
          </div>
        </div>
      <br />
      </div>
      <div>
        <div class="alert alert-success" style="text-align: center;"><b>Product List</b></div>
        <div class="table-responsive" style="text-align: center;">
          <table class="table table-striped">
            <thead>
            <tr>
              <th scope="col">#</th>
              <th scope="col">Product Name</th>
              <th scope="col">Description</th>
              <th scope="col">Cost</th>
              <th scope="col">Stock</th>
              <th scope="col">Action</th>
            </tr>
          </thead>
          <tbody>
            <tr *ngFor="let prd of ProductList | async; index as i">
              <th scope="row">{{ i + 1 }}</th>
              <td>{{prd.productName}}</td>
              <td>{{prd.productDescription}}</td>
              <td>{{prd.productPrice}}</td>
              <td>{{prd.productStock}}</td>
              <td><button type="button" class="btn1" matTooltip="Click Edit Button" (click)='ProductDetailsToEdit(prd.productId)'>Edit</button>
                |
                <button type="button" class="btn1" matTooltip="Click Delete Button" (click)="DeleteProduct(prd.productId)">Delete</button>
              </td>
            </tr>
          </tbody>
          </table>
        </div>
      </div>
      </div>
    </form>

User Component

user.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
import { Observable } from 'rxjs';
import { User } from '../Models/User';
import { UsersService } from './users.service';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {

  UserList?: Observable<User[]>;
  UserList1?: Observable<User[]>;
  userForm: any;
  userId = 0;

  constructor(private formbulider: FormBuilder,
     private userService: UsersService,private router: Router,
     private toastr: ToastrService) { }

  ngOnInit() {
    this.userForm = this.formbulider.group({
      userName: ['', [Validators.required]],
      address: ['', [Validators.required]]
    });
    this.getUserList();
  }
  getUserList() {
    this.UserList1 = this.userService.getUserList();
    this.UserList = this.UserList1;
  }
  PostUser(user: User) {
    const user_Master = this.userForm.value;
    this.userService.postUserData(user_Master).subscribe(
      () => {
        this.getUserList();
        this.userForm.reset();
        this.toastr.success('Data Saved Successfully');
      }
    );
  }
  UserDetailsToEdit(id: string) {
    this.userService.getUserDetailsById(id).subscribe(userResult => {
      this.userId = userResult.userId;
      this.userForm.controls['userName'].setValue(userResult.userName);
      this.userForm.controls['address'].setValue(userResult.address);
    });
  }
  UpdateUser(user: User) {
    user.userId = this.userId;
    const user_Master = this.userForm.value;
    this.userService.updateUser(user_Master).subscribe(() => {
      this.toastr.success('Data Updated Successfully');
      this.userForm.reset();
      this.getUserList();
    });
  }

  DeleteUser(id: number) {
    if (confirm('Do you want to delete this user?')) {
      this.userService.deleteUserById(id).subscribe(() => {
        this.toastr.success('Data Deleted Successfully');
        this.getUserList();
      });
    }
  }

  Clear(user: User){
    this.userForm.reset();
  }

}

user.component.html

<nav class="navbar navbar-expand-lg navbar navbar-dark bg-dark">
    <a class="navbar-brand" href="#">Users Application</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" routerLink="/">Home</a>
        </li>
        <li class="nav-item active">
          <a class="nav-link" routerLink="/products">Products</a>
        </li>
        <li class="nav-item active">
            <a class="nav-link" routerLink="/users">Users</a>
        </li>
      </ul>
    </div>
  </nav>
  
  <form class="form-horizontal" [formGroup]="userForm">
      <h1 style="text-align: center;">Welcome to Angular 14 CRUD with .NET 6 Web API</h1>
      <div>
      <div class="form-group">
        <label class="control-label col-sm-2" for="pwd">User Name:</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="txtUserName" formControlName="userName"
            placeholder="Name of User">
        </div>
      </div>
      <br />
      <div class="form-group">
        <label class="control-label col-sm-2" for="pwd">Address :</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="txtUserDescription" formControlName="address"
            placeholder="User Address">
        </div>
      </div>
      <br />
       <div class="form-group">
        <div class="container">
          <div class="row">
            <div class="col-sm">
              <button type="submit" class="btn btn-primary" (click)="PostUser(userForm.value)">Submit</button> 
            </div>
            <div class="col-sm">
              <button type="submit" class="btn btn-primary" (click)="UpdateUser(userForm.value)">Update</button>
            </div>
            <div class="col-sm">
              <button type="submit" class="btn btn-primary" (click)="Clear(userForm.value)">Clear</button>
            </div>
          </div>
        </div>
      <br />
      </div>
      <div>
        <div class="alert alert-success" style="text-align: center;"><b>User List</b></div>
        <div class="table-responsive" style="text-align: center;">
          <table class="table table-striped">
            <thead>
            <tr>
              <th scope="col">#</th>
              <th scope="col">User Name</th>
              <th scope="col">Address</th>
              <th scope="col">Action</th>
            </tr>
          </thead>
          <tbody>
            <tr *ngFor="let user of UserList | async; index as i">
              <th scope="row">{{ i + 1 }}</th>
              <td>{{user.userName}}</td>
              <td>{{user.address}}</td>
              <td><button type="button" class="btn1" matTooltip="Click Edit Button" (click)='UserDetailsToEdit(user.userId)'>Edit</button>
                |
                <button type="button" class="btn1" matTooltip="Click Delete Button" (click)="DeleteUser(user.userId)">Delete</button>
              </td>
            </tr>
          </tbody>
          </table>
        </div>
      </div>
      </div>
    </form>

Step 12

Finally, run the application

npm start

Homepage Component

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Product Component

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

User Component

Microservices with Ocelot Gateway Using .NET Core 6 API And Angular 14

Conclusion

In this article we discussed working of microservice architecture and ocelot API gateway using .NET Core 6 API, and went over step-by-step implementation of client applications using Angular 14.

Happy coding!