Showing posts with label Dotnet. Show all posts
Showing posts with label Dotnet. Show all posts

Sunday, April 5, 2026

Dotnet | Authorization Middleware

Authorization middleware doesn’t “guess” permissions—it evaluates policies against the authenticated user’s claims.

How it actually checks permissions, step by step 


1. It Reads Endpoint Metadata

When a request reaches authorization:

  • It looks at attributes like:
[Authorize]
[Authorize(Roles = "Admin")]
[Authorize(Policy = "CanEditProducts")]

This metadata is attached during routing.


2. It Uses the Authenticated User

From earlier middleware:

app.UseAuthentication();
  • HttpContext.User is already populated
  • Contains:
    • Claims (name, role, email, etc.)
    • Authentication status

If user is not authenticated →  immediately returns 401


3. It Builds an Authorization Policy

Each [Authorize] turns into a policy containing requirements:

Examples:

  • [Authorize] → must be authenticated
  • [Authorize(Roles = "Admin")] → must have role = Admin  (To be passed need Admin Role)
  • [Authorize(Policy = "CanEditProducts")] → custom rules (To be passed need Edit permission)

4. Policy is Evaluated by Authorization Service

Core component:

  • IAuthorizationService

It checks each requirement:

await authorizationService.AuthorizeAsync(user, resource, policy);

5. Requirements & Handlers

Each policy has:

  • Requirements (rules)
  • Handlers (logic to validate rules)
Example: Role check
[Authorize(Roles = "Admin")]

Internally checks:

user.IsInRole("Admin")

Example: Custom Policy
services.AddAuthorization(options =>
{
options.AddPolicy("CanEditProducts", policy =>
policy.RequireClaim("permission", "edit"));

});

Checks:

user.HasClaim("permission", "edit")

6. Decision Outcomes

Success

  • All requirements pass → request continues to controller

Failure cases:

  • Not authenticated → 401 Unauthorized
  • Authenticated but fails policy → 403 Forbidden

Full Flow 
Request → Authentication → Authorization → Controller

HttpContext.User

Check Policy/Claims

Allow or Block Request

Key Idea (Very Important)

Authorization is basically:

“Does this user’s claims satisfy the policy requirements?”


Real-Life Example

Request:

GET /admin/dashboard

Controller:

[Authorize(Roles = "Admin")]

User claims:

{
"name": "John",
"role": "User"
}

Result:

  • Authenticated →  Pass
  • Not in Admin role 
    403 Forbidden

In One Line

Authorization middleware checks permissions by:

Comparing user claims against policy requirements using handlers

Dotnet | Some Common Important Middleware

Authentication, Authorization, Static Files, and Routing middleware work together in ASP.NET Core.


Basic Pipeline Setup (Program.cs)
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://example.com"; // identity provider
options.Audience = "api";
});

builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
policy.RequireRole("Admin"));
});

builder.Services.AddControllers();

var app = builder.Build();

// Middleware pipeline
app.UseStaticFiles(); // 1. Serve static files
app.UseRouting(); // 2. Match routes

app.UseAuthentication(); // 3. Identify user
app.UseAuthorization(); // 4. Check permissions

app.MapControllers(); // 5. Execute endpoint

app.Run();

1. Static Files Middleware

Serves files from wwwroot

app.UseStaticFiles();

Note: No need of registering in builder.Servies as framework already added some default
features which are enough to work Static files middleware.
Example request:
GET /logo.png

If file exists:

wwwroot/logo.png → returned directly

Skips authentication, authorization, controllers → very fast


2. Routing Middleware

Decides which endpoint should handle the request

app.UseRouting();

Note: No need of registering in builder.Servies as framework already
added it when controllers middleware get added (builder.Services.AddControllers())
Example:
[HttpGet("products/{id}")]
public IActionResult GetProduct(int id)

Request:

GET /products/10

Routed to:

GetProduct(10)

3. Authentication Middleware

Identifies the user

app.UseAuthentication();

Example request:
GET /products
Authorization: Bearer <token>
 Middleware:
  • Validates token
  • Creates HttpContext.User

If valid:

User.Identity.IsAuthenticated = true

If missing/invalid:

User = anonymous

4. Authorization Middleware

Checks permissions

app.UseAuthorization();

Controller example:
[Authorize(Policy = "AdminOnly")]
[HttpGet("admin")]
public IActionResult GetAdminData()
{
return Ok("Secret data");
}
Behavior:
  • User is Admin →  allowed
  • User not Admin →  403 Forbidden
  • Not logged in →  401 Unauthorized

End-to-End Flow Example

Request 1 (Static file)
GET /logo.png

Flow:

StaticFiles → Response returned

Request 2 (Public API)
GET /products/1

Flow:

Routing → Controller → Response

(No auth required)


Request 3 (Protected API)
GET /admin
Authorization: Bearer valid-token

Flow:

Routing → Authentication → Authorization → Controller → Response

Request 4 (Unauthorized user)
GET /admin
(no token)

Flow:

Routing → Authentication(failed) → Authorization → 401

Quick Summary Table

MiddlewarePurposeExample Outcome
Static FilesServe files directly/logo.png
RoutingMatch URL to endpoint/products/1 → method
AuthenticationIdentify userValid JWT → user
AuthorizationCheck permissionsAdmin role required

Easy Way to Remember
  • StaticFiles → “Just give the file”
  • Routing → “Where should this go?”
  • Authentication → “Who are you?”
  • Authorization → “Are you allowed?”

Dotnet | Request Pipeline

A request in .NET Core (now commonly called ASP.NET Core) flows through a well-defined pipeline. Think of it as a chain of steps that process an HTTP request and produce a response.



Here’s the flow in a clear, conceptual way:


1. Client Sends HTTP Request

A browser, mobile app, or API client sends an HTTP request:

  • URL (e.g., /api/products)
  • Method (GET, POST, etc.)
  • Headers, body

2. Web Server (Kestrel)

The request first hits the built-in web server:

  • Kestrel
  • It listens for incoming HTTP requests and forwards them to the app

Optionally, Kestrel can sit behind:

  • IIS
  • Nginx

3. Middleware Pipeline (Core of the Flow)

This is the most important part.

Middleware are components executed in sequence. Each one can:

  • Handle the request
  • Modify it
  • Pass it to the next middleware

Typical pipeline setup (in Program.cs):

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
Flow inside middleware:
Request → Middleware 1 → Middleware 2 → Middleware 3 → Endpoint
← Response flows back
Common middleware:
  • Exception handling
  • Static files
  • Routing
  • Authentication & Authorization

4. Routing

Routing determines which endpoint should handle the request.

  • Matches URL pattern
  • Maps to a controller/action or minimal API

Example:

[HttpGet("products/{id}")]
public IActionResult GetProduct(int id)

5. Endpoint Execution

Once matched, the request reaches:

Option A: Controllers (MVC/Web API)
  • Controller class handles request
  • Action method executes logic
Option B: Minimal APIs
app.MapGet("/hello", () => "Hello World");

6. Model Binding & Validation

Before the action runs:

  • Data from request (JSON, query, route) is converted into C# objects
  • Validation attributes are applied

7. Business Logic & Services

Inside the action:

  • Calls services (via Dependency Injection)
  • Interacts with database, APIs, etc.

8. Response Creation

The action returns:

  • JSON (Ok(object))
  • View (MVC)
  • Status codes

9. Response Travels Back Through Middleware

The response goes back through the same middleware in reverse order:

  • Logging
  • Error handling
  • Response modification

10. Response Sent to Client

Finally:

  • Kestrel sends the HTTP response back to the client

Quick Summary (Flow)
Client → Kestrel → Middleware → Routing → Endpoint → Business Logic
←──────────── Response (back through middleware) ───────────

Key Concepts to Remember
  • Middleware = pipeline backbone
  • Routing decides where to go
  • Controllers/Endpoints handle logic
  • Dependency Injection is used everywhere

Dotnet | Minimal API

A Minimal API lets you define endpoints directly in Program.cs using simple methods.


Example
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World");

app.MapGet("/products/{id}", (int id) =>
{
return $"Product Id: {id}";
});

app.Run();

What’s happening?
  • MapGet → defines an HTTP GET endpoint
  • No controller, no action methods
  • Everything is defined inline

Key Features

1. Less boilerplate

No need for:

  • Controllers
  • Attributes like [HttpGet]

2. Fast to build
  • Great for small APIs
  • Quick prototypes

3. Built-in dependency injection
app.MapGet("/data", (IMyService service) =>
{
return service.GetData();
});

4. Supports all HTTP methods
app.MapPost("/products", (Product p) => { });
app.MapPut("/products/{id}", (int id) => { });
app.MapDelete("/products/{id}", (int id) => { });

Minimal API vs Controller API

FeatureMinimal APIController API
Code sizeVery smallMore boilerplate
StructureFlatLayered (Controllers)
Best forSmall / simple APIsLarge / enterprise apps
FlexibilityModerateHigh

When to Use Minimal API?

Good for:
  • Microservices
  • Simple CRUD APIs
  • Prototypes
  • Serverless functions

Not ideal for:
  • Large complex applications
  • Apps needing strict architecture (Controllers, Filters, etc.)

Real-World Example
app.MapGet("/users/{id}", async (int id, AppDbContext db) =>
{
var user = await db.Users.FindAsync(id);
return user is not null ? Results.Ok(user) : Results.NotFound();
});

Analogy
  • Minimal API = writing a quick note 
  • Controller API = writing a structured document 

Key Takeaway

Minimal API:

  • Removes ceremony
  • Focuses on simplicity and speed
  • Still uses full power of ASP.NET Core under the hood

Saturday, April 4, 2026

Dotnet | Kestrel

 In ASP.NET Core, Kestrel is the default cross-platform web server used to run your application.


What is Kestrel?

Kestrel is:

  • A lightweight, high-performance web server
  • Built into ASP.NET Core
  • Responsible for handling HTTP requests and responses

Simple Explanation

When a user opens your website:

Browser → Kestrel → ASP.NET Core App → Response → Browser

Kestrel is the engine that listens to requests and sends responses.


Key Features

1. Cross-platform

Runs on:
  • Windows
  • Linux
  • macOS

2. High Performance
  • Built for speed (used in production systems)
  • Handles thousands of requests efficiently

3. Supports HTTP protocols
  • HTTP/1.1
  • HTTP/2
  • HTTP/3 (modern apps)

4. Async & non-blocking
  • Designed for scalable apps

Where is Kestrel Used?

By default in every ASP.NET Core app:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run();

✔ This automatically starts Kestrel


Kestrel vs IIS

FeatureKestrelIIS (Internet Information Services)
TypeLightweight web serverFull-featured web server
PlatformCross-platformWindows only
UsageDefault in ASP.NET CoreOften used as reverse proxy

Production Setup

Common architecture:

Client → IIS / Nginx → Kestrel → App
  • Nginx or IIS acts as:
    • Reverse proxy
    • Load balancer
  • Kestrel handles app logic

Why not expose Kestrel directly?

Kestrel alone:

  • Doesn’t handle advanced security features
  • No built-in load balancing
  • Limited edge features
So we use:
  • IIS (Windows)
  • Nginx (Linux)

    Load balancing at IIS/Nginx

    Distributing incoming requests across multiple app instances

    Client → Nginx / IIS → App1 (Kestrel)
    → App2 (Kestrel)
    → App3 (Kestrel)

    How Nginx Does It (Simple Example)
    upstream myapp {
    server localhost:5000;
    server localhost:5001;
    }

    server {
    location / {
    proxy_pass http://myapp;
    }
    }

    Nginx or  IIS:

    • Receives request
    • Sends it to one of many Kestrel instances

    Analogy
    • Kestrel = Engine of a car 
    • IIS/Nginx = Driver + security + traffic control 

    Key Takeaway

    Kestrel is:

    • The core web server in ASP.NET Core
    • Fast, lightweight, and cross-platform
    • Usually sits behind a reverse proxy in production

    Dotnet | Exception Handling

    In ASP.NET Core, handling exceptions globally ensures you don’t scatter try-catch blocks everywhere and still return consistent responses.

    There are two main approaches:

    1. Built-in: 
    app.UseExceptionHandler("/error")

    What it does:
    This is a built-in middleware that catches unhandled exceptions and redirects to a specific endpoint.

    Example

    In Program.cs:
    app.UseExceptionHandler("/error");
    Error endpoint:
    [Route("/error")]
    public IActionResult HandleError()
    {
    return Problem("Something went wrong!");
    }

    How it works:
    • Exception occurs anywhere in pipeline
    • Middleware catches it
    • Redirects to /error
    • You return a response (JSON, view, etc.)

    Pros:
    • Very simple to use
    • Built-in and reliable
    • Good for basic/global handling

    Cons:
    • Less control
    • Harder to customize per exception type
    • Redirect-based (less flexible for APIs)

    2. Custom Exception Middleware (Recommended)

    What it is:
    You write your own middleware to handle exceptions exactly how you want.

    Example
    public class ExceptionMiddleware
    {
    private readonly RequestDelegate _next;

    public ExceptionMiddleware(RequestDelegate next)
    {
    _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
    try
    {
    await _next(context);
    }
    catch (Exception ex)
    {
    context.Response.StatusCode = 500;
    context.Response.ContentType = "application/json";

    await context.Response.WriteAsync(
    $"Error: {ex.Message}");
    }
    }
    }
    Register it:
    app.UseMiddleware<ExceptionMiddleware>();

    How it works:
    • Wraps entire request pipeline
    • Catches exceptions
    • Returns custom response directly

    Pros:
    • Full control
    • Can handle different exception types differently
    • Best for APIs (JSON responses)
    • Can add logging, correlation IDs, etc.

    Cons:
    • More code
    • You must maintain it

    Key Differences

    FeatureUseExceptionHandlerCustom Middleware
    SetupVery easyRequires code
    FlexibilityLimitedFull control
    Custom responsesBasicAdvanced
    API-friendlyModerateExcellent
    Exception-specificHardEasy

    Real-World Recommendation

    Use UseExceptionHandler when:
    • Simple app
    • MVC with views
    • Quick setup needed

    Use Custom Middleware when:
    • Building REST APIs
    • Need structured JSON errors
    • Want logging + monitoring

    Best Practice (Common in real apps)

    👉 Combine both:

    if (!app.Environment.IsDevelopment())
    {
    app.UseExceptionHandler("/error");
    }

    app.UseMiddleware<ExceptionMiddleware>();

    Bonus: Handling Specific Exceptions
    catch (KeyNotFoundException ex)
    {
    context.Response.StatusCode = 404;
    }
    catch (UnauthorizedAccessException ex)
    {
    context.Response.StatusCode = 401;
    }

    Simple Analogy
    • UseExceptionHandler = Default customer support desk 
    • Custom middleware = Your own trained support team 

    Final Takeaway

    👉 For Real projects:

    • Mention both
    • Prefer custom middleware for APIs
    • Add logging (Serilog, etc.) in middleware
                                  --------------------------------------------------------------------------------------

    Production-Ready Exception Middleware

    using System.Net;
    using System.Text.Json;

    public class GlobalExceptionMiddleware
    {
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;

    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
    {
    _next = next;
    _logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
    try
    {
    await _next(context);
    }
    catch (Exception ex)
    {
    _logger.LogError(ex, "Unhandled exception occurred");

    await HandleExceptionAsync(context, ex);
    }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception ex)
    {
    var statusCode = ex switch
    {
    KeyNotFoundException => HttpStatusCode.NotFound,
    UnauthorizedAccessException => HttpStatusCode.Unauthorized,
    ArgumentException => HttpStatusCode.BadRequest,
    _ => HttpStatusCode.InternalServerError
    };

    var response = new
    {
    success = false,
    message = ex.Message,
    statusCode = (int)statusCode
    };

    context.Response.ContentType = "application/json";
    context.Response.StatusCode = (int)statusCode;

    var json = JsonSerializer.Serialize(response);

    return context.Response.WriteAsync(json);
    }
    }

    Register Middleware
    app.UseMiddleware<GlobalExceptionMiddleware>();

    Place it early in the pipeline (before other middlewares).


    Sample JSON Response
    {
    "success": false,
    "message": "Product not found",
    "statusCode": 404
    }

    Enhancements (Real-World Level)

    1. Hide sensitive errors in Production
    message = env.IsDevelopment() ? ex.Message : "Something went wrong"

    2. Add Trace ID (VERY IMPORTANT for debugging)
    traceId = context.TraceIdentifier

    3. Use custom exception classes
    public class NotFoundException : Exception
    {
    public NotFoundException(string message) : base(message) { }
    }

    Then:

    NotFoundException => HttpStatusCode.NotFound

    4. Structured Logging (Serilog)

    Works great with:

    • Serilog
    • ELK / Seq dashboards

    Best Practice Architecture

    In real enterprise apps:

    • Controllers → throw exceptions
    • Middleware → handles everything
    • Logging → centralized
    • Response → consistent JSON

    Summarized Paragraph:

    👉 “I use custom global exception middleware in ASP.NET Core to handle exceptions centrally. It logs errors, maps exceptions to proper HTTP status codes, and returns structured JSON responses. For simple apps, UseExceptionHandler can be used, but middleware provides more flexibility.”

    Node | process.nextclick

    process.nextTick() schedules a callback to run immediately after the current operation , before the event loop continues . It runs: Befor...