Saturday, October 11, 2025

๐Ÿงฑ Understanding the Core Building Blocks of Angular

 

๐ŸŒŸ Introduction

Angular is one of the most powerful front-end frameworks used for developing modern single-page applications (SPAs). What makes Angular unique is its structured architecture, which is built upon several key building blocks.

In this article, we’ll explore these core Angular building blocks—Modules, Components, Templates, Directives, Services, Pipes, and Routing—with clear explanations and examples to help you understand how they all work together.


1. ๐Ÿงฉ Modules (NgModule)

Modules are the organizational units of an Angular application. They group related components, directives, pipes, and services together into a cohesive block of functionality.

Every Angular app has at least one root module called AppModule, defined in the app.module.ts file.

✅ Example:

@NgModule({ declarations: [AppComponent, HomeComponent], imports: [BrowserModule, FormsModule], bootstrap: [AppComponent] }) export class AppModule { }

๐Ÿ’ก Purpose:

  • Organizes code into functional areas.

  • Supports lazy loading for better performance.

  • Simplifies dependency management.


2. ⚙️ Components

Components are the heart of Angular applications. Each component controls a specific section of the UI and defines its behavior and appearance.

A component is made up of:

  • HTML Template (View)

  • TypeScript Class (Logic)

  • CSS/SCSS Styles (Design)

✅ Example:

@Component({ selector: 'app-hello', template: `<h1>Hello {{name}}!</h1>`, styles: [`h1 { color: blue; }`] }) export class HelloComponent { name = 'Angular'; }

๐Ÿ’ก Purpose:

  • Defines the UI logic and view.

  • Reusable across the application.

  • Connects data and behavior using data binding.


3. ๐Ÿงพ Templates

Templates define what the user sees in the browser. They combine HTML with Angular directives, pipes, and binding expressions.

✅ Example:

<div *ngIf="isLoggedIn"> Welcome, {{ userName | uppercase }} </div>

๐Ÿ’ก Purpose:

  • Defines the layout and structure of the component.

  • Uses data binding ({{ }}) and directives (*ngIf, *ngFor) to make the view dynamic.


4. ๐Ÿงญ Directives

Directives are used to add behavior or modify DOM elements in the template.

๐Ÿงฑ Types of Directives:

  1. Structural Directives – Change the structure of the DOM (*ngIf, *ngFor)

  2. Attribute Directives – Change the appearance or behavior of elements ([ngClass], [ngStyle])

✅ Example:

<p *ngIf="showMessage">Hello Angular!</p> <button [disabled]="!isActive">Click Me</button>

๐Ÿ’ก Purpose:

  • Enhance HTML elements dynamically.

  • Add custom interactive behaviors.


5. ๐Ÿง  Services & Dependency Injection

Services are used to share data or logic across multiple components. They are the backbone of business logic in Angular.

They often handle tasks like API calls, data fetching, and application-wide state management.

✅ Example:

@Injectable({ providedIn: 'root' }) export class DataService { getData() { return ['Apple', 'Banana', 'Cherry']; } }

๐Ÿ’ก Purpose:

  • Promote code reusability.

  • Keep components lightweight.

  • Implement Dependency Injection (DI) for efficiency.


6. ๐ŸŒ Routing

Routing enables navigation between different views or pages without reloading the entire application. It’s what makes Angular apps behave like single-page applications.

✅ Example:

const routes: Routes = [ { path: 'home', component: HomeComponent }, { path: 'about', component: AboutComponent } ];

๐Ÿ’ก Purpose:

  • Manages navigation within the app.

  • Supports lazy loading and guarding routes for security.


7. ๐Ÿ”„ Pipes

Pipes are used to transform data before displaying it in the template. Angular provides several built-in pipes such as uppercase, date, and currency. You can also create custom pipes.

✅ Example:

<p>{{ today | date:'fullDate' }}</p>

๐Ÿ’ก Purpose:

  • Simplify data formatting in templates.

  • Reusable and easy to integrate.


๐Ÿ“‹ Summary Table

Building BlockDescriptionExample
ModuleOrganizes the application into logical unitsAppModule
ComponentDefines UI and logicHomeComponent
TemplateDefines the view’s HTML<h1>{{title}}</h1>
DirectiveAdds behavior to elements*ngFor, *ngIf
ServiceShares data or logicDataService
RoutingManages navigation/home, /about
PipeFormats or transforms data`{{name

๐ŸŽฏ Conclusion

Angular’s building blocks work together to create a powerful, maintainable, and scalable application structure.
By mastering Modules, Components, Templates, Directives, Services, Pipes, and Routing, developers can build high-performing web applications with ease and flexibility.

Whether you’re a beginner or an experienced developer, understanding these building blocks is the first step toward becoming an Angular expert

Thursday, October 9, 2025

๐Ÿง  What is Generics in C#? Complete Guide with Examples

 ๐Ÿ“˜ Introduction

In C#, Generics are one of the most powerful features introduced with the .NET Framework 2.0.
They allow you to define classes, methods, interfaces, and collections that can work with any data type — while still maintaining type safety and performance.

In simple words, Generics help you write code once and use it with any data type.


⚙️ What Are Generics?

Generics let you define a placeholder type (called a type parameter) that will be replaced with a specific type when you create an instance of a class or call a method.

This means you can write:

List<int> List<string> List<Employee>

—all using the same generic List<T> class.


๐Ÿ’ก Example Without Generics

public class Calculator { public int Add(int a, int b) { return a + b; } }

If you want to add float or double values, you’ll have to write multiple methods for each data type.
This leads to code duplication and poor reusability.


⚙️ Example With Generics

public class Calculator<T> { public T Add(T a, T b) { dynamic x = a; dynamic y = b; return x + y; } } class Program { static void Main() { Calculator<int> intCalc = new Calculator<int>(); Console.WriteLine("Sum (int): " + intCalc.Add(10, 20)); Calculator<double> doubleCalc = new Calculator<double>(); Console.WriteLine("Sum (double): " + doubleCalc.Add(10.5, 20.7)); } }

Output

Sum (int): 30 Sum (double): 31.2

Here, T is a type parameter. It allows the Calculator class to operate with any data type (int, double, string, etc.).


๐Ÿงฑ Generic Method Example

You can also create generic methods inside normal classes.

public class DisplayData { public void ShowData<T>(T data) { Console.WriteLine("Value: " + data); } } class Program { static void Main() { DisplayData obj = new DisplayData(); obj.ShowData<int>(101); obj.ShowData<string>("Hello Generics"); } }

Output

Value: 101 Value: Hello Generics

Here, the method ShowData<T>() can accept any data type without overloading.


๐Ÿ“š Generic Collections in C#

C# provides several built-in generic collections inside the System.Collections.Generic namespace.
These are type-safe and more efficient than old non-generic collections like ArrayList or Hashtable.

Generic CollectionDescription
List<T>Dynamic array of type T
Dictionary<TKey, TValue>Key-value pair collection
Queue<T>FIFO (First-In-First-Out) collection
Stack<T>LIFO (Last-In-First-Out) collection

Example:

List<string> names = new List<string>(); names.Add("Hasitha"); names.Add("Cherry"); foreach (var name in names) { Console.WriteLine(name); }

Output

Hasitha Cherry

๐Ÿงฉ Benefits of Generics in C#

BenefitDescription
Type SafetyPrevents type mismatches at compile time
PerformanceAvoids boxing/unboxing for value types
ReusabilityWrite code once, use with any type
MaintainabilityCleaner and less repetitive code

๐Ÿ”„ Generic Constraints (Optional but Powerful)

Sometimes, you might want to restrict which data types can be used with your generic class.

Example:

public class DataManager<T> where T : class { public void Display(T data) { Console.WriteLine("Data: " + data); } }

Here, where T : class means only reference types can be used.


๐Ÿš€ Conclusion

Generics in C# make your code reusable, efficient, and type-safe.
They help developers build scalable and maintainable applications, especially in large projects using .NET Core or ASP.NET.

๐Ÿงฉ Understanding Adapter Design Pattern in Software Development


๐Ÿ” Introduction

In modern software architecture, systems often need to integrate with third-party libraries, legacy code, or APIs that don’t match our application's interface. The Adapter Design Pattern is a structural design pattern that bridges this gap by converting one interface into another that the client expects.

Simply put, it acts as a translator between incompatible interfaces — allowing two systems to work together smoothly without modifying their existing code.


๐Ÿ’ก Real-Time Example: Power Plug Adapter

Imagine you travel from India (which uses a 3-pin plug) to the US (which uses a 2-pin socket). You can’t directly plug your Indian charger into the US socket — you need an adapter.

Similarly, in software:

  • Client → Your laptop charger (expects 3-pin socket).

  • Service / API → The US socket (2-pin).

  • Adapter → A converter that connects both.

This is exactly what the Adapter Pattern does in programming — it adapts one interface to another.


๐Ÿง  Technical Explanation

The Adapter Design Pattern involves three main components:

  1. Target Interface – The interface expected by the client.

  2. Adaptee – The existing class with a different interface.

  3. Adapter – A class that bridges the Adaptee with the Target interface.


๐Ÿ’ป Example in C#

// Target Interface public interface INewPaymentGateway { void MakePayment(string account, double amount); } // Adaptee (Old system) public class OldPaymentSystem { public void ProcessTransaction(string customerCode, double value) { Console.WriteLine($"Payment of {value} processed for {customerCode} in Old System."); } } // Adapter Class public class PaymentAdapter : INewPaymentGateway { private readonly OldPaymentSystem _oldPaymentSystem; public PaymentAdapter(OldPaymentSystem oldPaymentSystem) { _oldPaymentSystem = oldPaymentSystem; } public void MakePayment(string account, double amount) { // Translate the request _oldPaymentSystem.ProcessTransaction(account, amount); } } // Client class Program { static void Main() { INewPaymentGateway payment = new PaymentAdapter(new OldPaymentSystem()); payment.MakePayment("USER123", 2500); } }

Output:

Payment of 2500 processed for USER123 in Old System.

✅ The PaymentAdapter bridges the old payment system (OldPaymentSystem) with the new interface (INewPaymentGateway).


๐Ÿš€ Importance of Adapter Design Pattern

  • Integration Friendly: Easily integrate legacy systems with new applications.

  • Loose Coupling: Promotes flexibility by decoupling client and adaptee.

  • Reusability: Reuse existing incompatible code without rewriting it.

  • Scalability: Makes systems scalable for future interface changes.


๐Ÿงฉ Real-Time Use Cases

  • Connecting different payment gateways (PayPal, Stripe, Razorpay).

  • Integrating legacy APIs in new microservices.

  • Adapting different database connectors or logging frameworks.

  • In cloud or Azure services, when bridging old APIs to new versions.


๐Ÿ Conclusion

The Adapter Design Pattern is a vital bridge for compatibility in software integration. It allows modern systems to interact with legacy code, third-party APIs, and incompatible interfaces — without rewriting the entire system. This ensures flexibility, maintainability, and reusability, key principles of robust software architecture.

Notification Flow in Microservices

 In a microservices architecture, services are decoupled. So if you want to notify a user about an event (like "order processed"), you usually use an asynchronous messaging system rather than calling services directly.

Flow Overview

  1. Event happens in a microservice
    Example: OrderService processes an order.

    var orderProcessedEvent = new OrderProcessedEvent { OrderId = 123, UserId = 456 };
  2. Publish Event to Message Broker

    • Microservice publishes the event to Azure Service Bus topic/queue.

    • Topics allow multiple subscribers, queues deliver to one consumer.

  3. Notification Service Subscribes

    • A dedicated Notification Microservice subscribes to the topic/queue.

    • When a message arrives, it triggers notification logic (email, SMS, push).

  4. Send Notification to Users

    • Notification Service decides which users should get notified.

    • It uses user preferences/configurations stored in a database.

  5. Delivery

    • Email: via SMTP, SendGrid, or Azure Communication Services.

    • Push: via Firebase or Azure Notification Hub.

    • SMS: via Twilio, Azure Communication Services, etc.


2. Azure Service Bus Setup

  • Queues: point-to-point (one consumer).

  • Topics & Subscriptions: publish-subscribe pattern (multiple consumers can get the same event).

Example:

  • OrderProcessedTopic

    • Subscription 1 → NotificationService

    • Subscription 2 → AnalyticsService

// Publishing var client = new ServiceBusClient(connectionString); var sender = client.CreateSender("OrderProcessedTopic"); await sender.SendMessageAsync(new ServiceBusMessage(JsonSerializer.Serialize(orderProcessedEvent)));
// Subscribing in Notification Service var processor = client.CreateProcessor("OrderProcessedTopic", "NotificationSubscription"); processor.ProcessMessageAsync += async args => { var body = args.Message.Body.ToString(); var orderEvent = JsonSerializer.Deserialize<OrderProcessedEvent>(body); // Send notification logic await SendEmailNotification(orderEvent.UserId, "Order Processed"); };

3. Email Notification Service

Components:

  1. Email Templates – HTML/Plain text templates.

  2. SMTP/Email Provider Configuration – SMTP settings (host, port, username, password) or a service like SendGrid/Azure Communication Services.

  3. Email Sending Logic – Called by the Notification Service when a message is received.

Sample code using SMTP:

public async Task SendEmailNotification(int userId, string message) { var user = await dbContext.Users.FindAsync(userId); if (user == null || string.IsNullOrEmpty(user.Email)) return; var smtp = new SmtpClient("smtp.yourmail.com") { Port = 587, Credentials = new NetworkCredential("username", "password"), EnableSsl = true, }; var mail = new MailMessage("noreply@yourapp.com", user.Email, "Order Update", message); await smtp.SendMailAsync(mail); }

4. Configuring Users for Notifications

  1. User Preferences Table

    • Table: UserNotifications

    • Columns: UserId, NotificationType, IsEnabled, Email, PushToken, PhoneNumber

    UserId | NotificationType | IsEnabled | Email | PushToken | PhoneNumber 456 | OrderProcessed | 1 | user@example.com | xyz | 9999999999
  2. Check Before Sending

    • Before sending, check if the user wants that type of notification:

    var config = dbContext.UserNotifications .Where(u => u.UserId == userId && u.NotificationType == "OrderProcessed" && u.IsEnabled) .FirstOrDefault(); if(config != null) SendEmail(...);
  3. Optional UI – Let users manage preferences in Settings → Notification Preferences.


5. Overall Flow Diagram

[OrderService] --(event)--> [Azure Service Bus Topic] --> [NotificationService] |--> Email/SMS/Push |--> Uses User Preferences from DB

Key Points:

  • Use Service Bus for decoupling services.

  • Use Notification Service as a central microservice.

  • Use user preferences to decide who gets notified.

  • Email provider can be SMTP, SendGrid, or Azure Communication Services.

  • Optional: extend for SMS, push notifications, or mobile apps.

Background Service in Micro Services - Complete Guide

 A background service that monitors a database for changes (like new orders) and then acts on them. I’ll explain the flow step by step, typical in a .NET Core + Web API + SQL Server environment.

1. What is a Background Service?

In .NET Core, a background service is a long-running process that executes independently of HTTP requests. It can continuously run in the background and perform tasks like:

  • Polling a database

  • Sending emails or notifications

  • Processing queues or orders

In .NET Core, we usually implement it using IHostedService or BackgroundService.


2. High-Level Flow for Database Polling

Imagine your scenario: the service checks for new orders and processes them.

  1. Database

    • Table: Orders

    • Columns: OrderId, CustomerId, Status, CreatedAt, etc.

    • New orders are inserted with Status = 'Pending'.

  2. Background Service (C#)

    • Runs continuously in the background.

    • Periodically checks the Orders table for Status = 'Pending'.

    • Picks up pending orders and updates them to Processing or triggers other actions.

  3. Processing Flow

    • Fetch orders:

      var pendingOrders = dbContext.Orders .Where(o => o.Status == "Pending") .ToList();
    • Process orders (e.g., send to shipping service, generate invoice, etc.)

    • Update status:

      order.Status = "Processed"; dbContext.SaveChanges();
  4. Notification (Optional)

    • Once processed, the service can send notifications via email, push notifications, or enqueue messages in a message broker like Azure Service Bus.


3. Sample Flow Diagram

Angular / Frontend | | [Customer places order] v SQL Server (Orders Table) | | [Background Service polls DB periodically] v .NET Core Background Service | |-- Fetch pending orders |-- Process orders |-- Update status |-- Send notifications (optional) v External services / APIs / Notifications

4. Polling vs Event-Driven Approach

  • Polling:
    The background service queries the database every N seconds/minutes. Simple but less efficient for large-scale systems.

  • Event-driven:
    Instead of polling, use a message broker (Azure Service Bus, RabbitMQ, Kafka).

    • Orders insert triggers a message.

    • Background service subscribes and processes only when a new order arrives.

    • More scalable and real-time.


5. Example: Implementing BackgroundService in .NET Core

public class OrderProcessingService : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; public OrderProcessingService(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { using var scope = _scopeFactory.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>(); var pendingOrders = await dbContext.Orders .Where(o => o.Status == "Pending") .ToListAsync(); foreach (var order in pendingOrders) { // Process order order.Status = "Processed"; } await dbContext.SaveChangesAsync(); // Wait for some time before next check await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); } } }

Summary of the Flow:

  1. Frontend inserts an order into SQL Server.

  2. Background service wakes up periodically.

  3. It queries the database for pending orders.

  4. Processes each order.

  5. Updates the order status.

  6. Optional: sends notifications or triggers other services.

  7. Repeats indefinitely.

Tuesday, October 7, 2025

๐Ÿ”‘ Where to Configure Ports in .NET Core

 There are 3 main ways:


1️⃣ launchSettings.json (Local Development Only)

  • Located in:
    Properties/launchSettings.json

Example:

{ "profiles": { "ProductService": { "commandName": "Project", "dotnetRunMessages": true, "applicationUrl": "http://localhost:5002;https://localhost:7002", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }

๐Ÿ‘‰ This means:

  • ProductService will listen on http://localhost:5002 and https://localhost:7002.

  • Useful for local debugging.


2️⃣ appsettings.json or appsettings.{Environment}.json

  • You can configure Kestrel endpoints directly.

Example:

{ "Kestrel": { "Endpoints": { "Http": { "Url": "http://localhost:5002" }, "Https": { "Url": "https://localhost:7002" } } } }

๐Ÿ‘‰ This works in development, staging, and production.
๐Ÿ‘‰ More flexible, especially when deploying in Docker/Kubernetes.


3️⃣ Hardcode in Program.cs (Not Recommended for Production)

var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseUrls("http://localhost:5002", "https://localhost:7002"); var app = builder.Build(); app.MapControllers(); app.Run();

๐Ÿ‘‰ Quick way to bind to specific ports, but harder to manage in large deployments.


⚙️ Best Practices

  1. Local Development → use launchSettings.json.

  2. Production (IIS, Azure, Docker, Kubernetes)

    • Use appsettings.json (Kestrel:Endpoints).

    • Or environment variables → DOTNET_URLS=http://+:5002.

  3. Dockerized Microservices → expose ports in Dockerfile / docker-compose.yml. Example:

    EXPOSE 5002
    ports: - "5002:5002"

✅ Summary

  • launchSettings.json → local dev only.

  • appsettings.json (Kestrel) → preferred for production.

  • Program.cs → UseUrls() → quick overrides.

  • Environment Variables / Docker → best in containerized/cloud setups.

๐Ÿ”‘ Example: Ocelot API Gateway with JWT Authentication

 

1️⃣ Create Solution Structure

We’ll create 3 projects:

  1. AuthService → issues JWT tokens.

  2. ProductService → sample microservice.

  3. ApiGateway → Ocelot API Gateway.

dotnet new webapi -n AuthService dotnet new webapi -n ProductService dotnet new webapi -n ApiGateway

2️⃣ Implement AuthService (JWT Token Issuer)

Install NuGet packages

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package System.IdentityModel.Tokens.Jwt

Add Token Generation (AuthController.cs)

using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { [HttpPost("login")] public IActionResult Login(string username, string password) { // Simple validation (replace with real DB check) if (username == "admin" && password == "password") { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes("SuperSecretKeyForJwt123456"); // store securely in secrets manager var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim("role", "Admin") }), Expires = DateTime.UtcNow.AddMinutes(30), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return Ok(new { token = tokenHandler.WriteToken(token) }); } return Unauthorized(); } }

3️⃣ Implement ProductService (Protected Microservice)

Add a Controller (ProductsController.cs)

using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { [Authorize] [HttpGet] public IActionResult GetProducts() { return Ok(new[] { new { Id = 1, Name = "T-shirt", Price = 499 }, new { Id = 2, Name = "Jeans", Price = 999 } }); } }

Configure JWT Authentication in Program.cs

using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; var builder = WebApplication.CreateBuilder(args); var key = Encoding.ASCII.GetBytes("SuperSecretKeyForJwt123456"); builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; }); builder.Services.AddControllers(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();

4️⃣ Configure API Gateway (Ocelot)

Install Ocelot

dotnet add package Ocelot dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Add ocelot.json

{ "Routes": [ { "DownstreamPathTemplate": "/api/products", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5002 } // ProductService port ], "UpstreamPathTemplate": "/products", "UpstreamHttpMethod": [ "Get" ], "AuthenticationOptions": { "AuthenticationProviderKey": "TestKey", "AllowedScopes": [] } } ], "GlobalConfiguration": { "BaseUrl": "https://localhost:5000" } }

Configure Program.cs in ApiGateway

using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Ocelot.DependencyInjection; using Ocelot.Middleware; using System.Text; var builder = WebApplication.CreateBuilder(args); var key = Encoding.ASCII.GetBytes("SuperSecretKeyForJwt123456"); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer("TestKey", x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; }); builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true); builder.Services.AddOcelot(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); await app.UseOcelot(); app.Run();

5️⃣ Test Flow

  1. Get Token

    POST https://localhost:5001/api/auth/login Body: { "username": "admin", "password": "password" }

    Response → { "token": "eyJhbGci..." }

  2. Call Product API via Gateway

    GET https://localhost:5000/products Authorization: Bearer eyJhbGci...

    ✅ Response → [ { "Id": 1, "Name": "T-shirt", "Price": 499 }, ... ]

  3. Without Token → 401 Unauthorized.


๐Ÿš€ Summary

  • AuthService issues JWT.

  • ProductService validates JWT.

  • ApiGateway (Ocelot) sits in front, validates tokens, and routes traffic.

Blog Archive

Don't Copy

Protected by Copyscape Online Plagiarism Checker

Pages