Routing in ASP.NET Core.

Routing is a fundamental concept in ASP.NET Core that enables the framework to map incoming HTTP requests to specific endpoints in your application. It plays a crucial role in defining how URLs are structured and how they correspond to the actions in your application. This article will provide a detailed overview of routing in ASP.NET Core, including its types, configuration, and examples.

What is Routing?

Routing is the process of directing an incoming HTTP request to the appropriate handler based on the URL and HTTP method. In ASP.NET Core, routing is handled by the middleware, which inspects the request and matches it against defined routes.

Which Middleware Handles Routing?

In ASP.NET Core, routing is handled by two key middleware components:

1. UseRouting() Middleware

  • Purpose: Matches the incoming HTTP request to the route template (defined via MapControllerRoute, attribute routing, etc.).
  • Placement: Must come before UseAuthorization() and UseEndpoints()

2. UseEndpoints() Middleware
  • Purpose: Executes the matched route handler (e.g., controller action, Razor page, minimal API).
  • It finalizes the routing decision made by UseRouting().

Types of Routing

ASP.NET Core supports two main types of routing:

  • Convention-based Routing: This is the default routing mechanism that uses predefined patterns to match incoming requests. It is typically used in MVC applications.
  • Attribute Routing: This allows developers to define routes directly on the controller actions using attributes. This method provides more control and flexibility over the routing configuration.

Key Note:
  • MapControllers(): Enables attribute routing ([Route("api/[controller]")])
  • MapControllerRoute(): Enables convention-based routing (like {controller}/{action}/{id?})

Convention-Based Routing in ASP.NET Core

Convention-based routing follows a predefined pattern to map incoming URLs to controller actions. This routing logic is configured centrally, usually in the Program.cs or Startup.cs file.

It's called “convention-based” because your app follows naming conventions for controllers, actions, and parameters to match the routes.

How to configure (Program.cs):
var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllersWithViews(); // For MVC
builder.Services.AddControllers(); // For Web API

var app = builder.Build();

// Configure the HTTP request pipeline
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

// Configure endpoints
app.UseEndpoints(endpoints =>
{
    // MVC Routing
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    // API Routing (attribute routing will be used)
    endpoints.MapControllers();
});

app.Run();
  • controller=Home: default controller
  • action=Index: default action
  • id?: optional parameter

Example:
public class ProductsController : Controller
{
    public IActionResult Details(int id)
    {
        return View(); // Returns View for /products/details/5
    }
}

Request:
GET /products/details/5

Matched By Pattern:
{controller=Products}/{action=Details}/{id=5}

Benefits of Convention-Based Routing:
  • Centralized route definitions
  • Easier to manage in large MVC apps
  • Reduces redundancy

Limitations:
  • Less flexible for APIs
  • It can become confusing with too many controllers/actions

Attribute Routing in ASP.NET Core

Attribute routing uses attributes directly on controller classes and action methods to define the routing rules. This provides more control and makes the routing explicit and readable.

Introduced in ASP.NET Web API and now standard in ASP.NET Core.

How To Use:
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok("All Products");
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        return Ok($"Product {id}");
    }

    [HttpPost]
    public IActionResult Create(Product product)
    {
        return Ok("Product Created");
    }
}

Request:

URL Method Action Called
GET /api/products [HttpGet] GetAll()
GET /api/products/2 [HttpGet("{id}")] GetById(2)
POST /api/products [HttpPost] Create()

Benefits of Attribute Routing:
  • Better suited for RESTful APIs
  • Greater clarity and control per action
  • Easy to document and maintain

How To Pass Multiple Values in a Request?

There are multiple ways to pass more than one parameter in a Request. Let's discuss each of them one by one:

1. Pass via Query String.
Query parameters are used to send data to the server in a key-value format. For example, in the URL:
https://localhost:5001/api/products?category=electronics&sort=price
The query parameters are category and sort, with values electronics and price, respectively.

You can access query parameters in your controller actions without needing to define them in the route. Here’s how you can do it:

Example of Using Query Parameters:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    private static readonly List<Product> _products = new()
    {
        new Product(1, "Laptop", 999.99m, "electronics"),
        new Product(2, "Mouse", 25.50m, "accessories"),
        new Product(3, "Smartphone", 699.99m, "electronics")
    };

    [HttpGet]
    public IActionResult Get([FromQuery] string category, [FromQuery] string sort)
    {
        var products = _products.AsQueryable();

        if (!string.IsNullOrEmpty(category))
        {
            products = products.Where(p => p.Category == category);
        }

        if (sort == "price")
        {
            products = products.OrderBy(p => p.Price);
        }

        return Ok(products.ToList());
    }
}

2. Pass Multiple values via Route Parameters.
In ASP.NET Core, you can pass multiple values via route parameters by defining them in the route template. This allows you to capture multiple segments of the URL as parameters in your controller action. Here’s how to do it:

To get a product by category and ID:
GET https://localhost:5001/api/products/electronics/1

Example of Using Query Parameter:
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    // Sample data
    private static readonly List<Product> _products = new()
    {
        new Product(1, "Laptop", "electronics"),
        new Product(2, "Mouse", "accessories"),
        new Product(3, "Smartphone", "electronics")
    };

    // Action method to get product by category and ID
    [HttpGet("{category}/{productId}")]
    public IActionResult GetProduct(string category, int productId)
    {
        var product = _products.FirstOrDefault(p => p.Id == productId && p.Category == category);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }
}

public record Product(int Id, string Name, string Category);

Bonus: For PUT/POST requests, we usually send JSON data in the body.
{
  "name": "Laptop",
  "price": 1500,
  "category": "Electronics"
}

Example Controller Action Method:
[HttpPost]
public IActionResult AddProduct([FromBody] Product product)
{
    // Access product.Name, product.Price, etc.
    return Ok($"Added: {product.Name}");
}

Note: You can only bind one complex object from the body using [FromBody]. If you need to pass multiple complex objects, wrap them into a single class.

Conclusion.

Understanding how routing works in ASP.NET Core Web API, especially the use of HTTP methods like GET, POST, and the power of attribute routing is essential for building clean, scalable, and RESTful services. By mapping specific URLs to controller actions using clear route definitions, you ensure that your API is both intuitive and maintainable

Understanding RESTful Principles in Web APIs.

In modern web development, RESTful APIs have become the standard for building scalable, stateless, and interoperable web services. At the heart of REST architecture are a set of HTTP methods — namely GET, POST, PUT, and DELETE — which define how clients interact with server resources.

In this article, you'll learn what each of these methods means, how they work, and when to use them with real-world examples using ASP.NET Core Web API.

What is REST?

REST (Representational State Transfer) is an architectural style for designing networked applications. It uses standard HTTP methods to perform CRUD operations (Create, Read, Update, Delete) on resources, which are usually represented as URLs.

A RESTful API is:
  • Stateless: Each request contains all the information needed.
  • Resource-based: Every piece of data is treated as a resource.
  • Uses standard HTTP verbs: GET, POST, PUT, DELETE, etc.

Core RESTful HTTP Methods

Let's break down the four primary HTTP methods used in RESTful APIs:

1. GET — Read Data

Purpose: Retrieve data from the server (read-only)
Safe and idempotent: Does not change server state
Status Code: 200 OK, 404 Not Found if the resource is missing

Example:
Request:
GET /api/products/1

Response:
{
  "id": 1,
  "name": "Laptop",
  "price": 1200
}

GET Request In ASP.NET Core:
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
    var product = _repo.GetById(id);
    if (product == null) return NotFound();
    return Ok(product);
}

2. POST — Create New Resource

Purpose: Send data to the server to create a new resource
Not idempotent: Calling multiple times will create multiple resources
Status Code: 201 Created

Example:
Request:
POST /api/products
Content-Type: application/json

{
  "name": "Tablet",
  "price": 500
}

Response:
201 Created
Location: /api/products/3

POST Request in ASP.NET Core:
[HttpPost]
public IActionResult CreateProduct(Product newProduct)
{
    _repo.Add(newProduct);
    return CreatedAtAction(nameof(GetProduct), new { id = newProduct.Id }, newProduct);
}

3. PUT — Update Existing Resource

Purpose: Update an existing resource entirely
Idempotent: The Same request can be repeated with the same result
Status Code: 200 OK, 204 No Content if no body returned

Example:
Request:
PUT /api/products/1
Content-Type: application/json

{
  "id": 1,
  "name": "Updated Laptop",
  "price": 1300
}

Response:
204 No Content

PUT Request in ASP.NET Core.
[HttpPut("{id}")]
public IActionResult UpdateProduct(int id, Product updatedProduct)
{
    if (id != updatedProduct.Id) return BadRequest();
    var existing = _repo.GetById(id);
    if (existing == null) return NotFound();

    _repo.Update(updatedProduct);
    return NoContent();
}

4. DELETE — Remove Resource

Purpose: Delete a resource by its ID
Idempotent: Deleting a non-existent item returns the same result
Status Code: 204 No Content, 404 Not Found

Example:
Request:
DELETE /api/products/1
ss
Response:
204 No Content

DELETE Request in ASP.NET Core:
[HttpDelete("{id}")]
public IActionResult DeleteProduct(int id)
{
    var product = _repo.GetById(id);
    if (product == null) return NotFound();

    _repo.Delete(id);
    return NoContent();
}

What Does Idempotent Mean in REST APIs?

Idempotent refers to an operation that can be repeated multiple times without changing the result beyond the initial application.
In the context of REST APIs and HTTP methods, an idempotent method ensures that:
"No matter how many times a client sends the same request, the result on the server remains the same."


Simple Example:

✅ DELETE /api/products/1

  • First request: Deletes product with ID 1 → returns 204 No Content.
  • Second request: Product already deleted → returns 404 Not Found.

💡 But the server state hasn’t changed after the second call, so DELETE is idempotent.


Understanding GET, POST, PUT, and DELETE is essential when working with RESTful APIs in ASP.NET Core or any modern backend framework. Each HTTP method serves a specific purpose and follows well-defined rules, making your API clean, maintainable, and developer-friendly.

Difference Between Web API and MVC in ASP.NET Core.

ASP.NET Core is a powerful framework developed by Microsoft that supports both Web APIs and MVC architecture. While they share many similarities in structure, configuration, and middleware, they serve different purposes and are used in distinct scenarios.

This article explains the key differences between ASP.NET Core Web API and ASP.NET Core MVC, their intended use cases, and how they are implemented.

What is ASP.NET Core MVC?

ASP.NET Core MVC (Model-View-Controller) is a framework for building dynamic web applications that return HTML views to the browser. It uses the MVC design pattern, where:
  • Model: Represents the application’s data and business logic.
  • View: Responsible for presenting the data (UI) to the user using Razor syntax.
  • Controller: Handles incoming HTTP requests, interacts with the model, and returns views or data.

Key Features of ASP.NET Core MVC
  • Built-in routing system (app.UseRouting(), MapControllerRoute)
  • Strong support for dependency injection
  • Tag Helpers and Razor views for dynamic HTML generation
  • Model binding and validation support
  • Supports RESTful API endpoints
  • Highly testable and modular architecture
Example Code:
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();  // Returns the "Index.cshtml" view
    }
}

View (Index.cshtml)
<h1>Welcome to ASP.NET Core MVC</h1>

Use Cases
  • Web portals and dashboards
  • Admin panels
  • E-commerce websites
  • Content Management Systems (CMS)

2. What is ASP.NET Core Web API?

ASP.NET Core Web API is designed for building HTTP-based RESTful services that return data only, usually in the form of JSON or XML. There are no views involved — only data exchange between client and server.

Key Features of ASP.NET Core Web API

  • Returns data instead of views
  • Lightweight and high-performance
  • Uses standard HTTP methods: GET, POST, PUT, DELETE
  • Built-in support for model binding, validation, dependency injection, and routing
  • Easily integrated with Swagger for API documentation

Use Case:
  • Backend services for mobile apps, SPAs (Angular/React), or microservices
  • Systems that require JSON-based APIs
  • Server-to-server communication
Example Code:

Step 1: Create a Model.
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
}

Step 2: Create the Controller.
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private static List<Product> products = new List<Product>
    {
        new Product { Id = 1, Name = "Laptop", Price = 1200 },
        new Product { Id = 2, Name = "Phone", Price = 800 }
    };

    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetAll()
    {
        return Ok(products);
    }

    [HttpGet("{id}")]
    public ActionResult<Product> GetById(int id)
    {
        var product = products.FirstOrDefault(p => p.Id == id);
        if (product == null)
            return NotFound();

        return Ok(product);
    }

    [HttpPost]
    public ActionResult AddProduct(Product newProduct)
    {
        products.Add(newProduct);
        return CreatedAtAction(nameof(GetById), new { id = newProduct.Id }, newProduct);
    }
}

Step 3: Configure the application (Program.cs)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers(); // Enables attribute routing for API

app.Run();

Testing the API
  • GET /api/products → Returns all products
  • GET /api/products/1 → Returns product with ID = 1
  • POST /api/products → Add a new product (via Postman or frontend)

ASP.NET Core Web API is ideal for building modern, scalable, and stateless RESTful services. It separates the UI from the logic and serves as the backend for many client apps.

Key Difference Between Web API and MVC in ASP.NET Core.

Aspect ASP.NET Core MVC ASP.NET Core Web API
Purpose Build dynamic web applications with UI Build RESTful services for data exchange
Output Returns HTML views using Razor Returns data like JSON or XML
View Engine Uses Razor (.cshtml) No view engine; returns data only
Return Type Returns View(), PartialView() Returns Ok(), NotFound(), Created(), etc.
[ApiController] attribute Not used Commonly used for automatic model binding and validation
Use Case Websites, Admin dashboards, CMS SPAs (Angular, React), Mobile apps, Microservices
Client Browsers that render HTML Frontend apps, Postman, mobile apps
HTTP Verbs Mainly GET and POST GET, POST, PUT, DELETE (RESTful)

While ASP.NET Core MVC and Web API share the same base framework and features like routing, middleware, and dependency injection, they serve different application layers. MVC is ideal for UI-based applications, whereas Web API is built for data exchange and service-based architectures.

launchSetting.json File in ASP.NET Core.

When you're building ASP.NET Core applications, your focus is usually on the core logic, APIs, UI, or database layers. But there's one small file quietly sitting in your project that can significantly improve your development experience, and that's the launchSettings.json file.

Suppose you've ever wondered how your app knows which port to run on, how to open Swagger by default when debugging, or how to simulate different environments like Development or Staging without changing your code. In that case, you're about to find your answer.

In this guide, you’ll learn what the launchSettings.json file does, how you can customize it, and how to use it to streamline your development workflow. Whether you're using Visual Studio, Visual Studio Code, or the .NET CLI, mastering this file will help you build, run, and test your applications more efficiently. Let's dive in!

What is launchSettings.json?

launchSettings.json is a development-only configuration file used by Visual Studio, Visual Studio Code, and the .NET CLI. It defines how your ASP.NET Core app starts during development, including which port to use, which server to run on (Kestrel or IIS Express), whether to open a browser, and even which environment variables to set.

This file allows you to configure:
  • Which server to use (like Kestrel or IIS Express)
  • What ports or URLs should your app listen to
  • Whether a browser should open when debugging starts
  • What environment variables should be set (like ASPNETCORE_ENVIRONMENT)
  • Which launch profile should be used (for different debugging scenarios)

It’s important to know that launchSettings.json is not used in production, and it only affects how your app runs locally while developing and debugging.

Where to Find launchSettings.json in ASP.NET Core?

When you create a new ASP.NET Core project using Visual Studio or the .NET CLI, a file named launchSettings.json is automatically created for you.

Path to Find:
YourProjectFolder/
└── Properties/
    └── launchSettings.json

So if your project is named MyWebApp, you’ll find the file at:
MyWebApp/Properties/launchSettings.json

launchSettings.json file path

If it's missing, don’t worry — you can create it manually inside the Properties folder, or let Visual Studio regenerate it by enabling project debugging or launch profiles.

Understanding the Structure of launchSettings.json.

launchSettings.json structure is designed around the concept of profiles, each representing a different way your app can be launched, such as through Kestrel, IIS Express, or Docker.

launchSettings.json File
{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:9866",
      "sslPort": 0
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5155",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
Now let’s break down each part in detail.

1. Profiles Section

At the heart of the file is the profiles object. Think of each profile as a self-contained configuration unit that describes a launch mode.
  • Each profile has a name (e.g., "IIS Express", "MyApi").
  • Profiles are typically tied to how the developer intends to run or test the application in a specific context.
  • You might have one profile for API testing and another for UI debugging, all isolated yet contained in the same file.
You can select your profile from the start button of Visual Studio as shown below:

launchSettings.json profile Setting

2. commandName

The commandName within a profile acts as the execution strategy. It determines what kind of host will launch your app.
Theoretical values include:
  • "Project": Indicates the app should run using the default Kestrel web server.
  • "IISExpress": Used when the app is hosted via IIS Express (Windows-specific).
  • "Docker": Used when your app is containerized and launched via Docker tools.
  • "Executable": Allows launching an external executable instead of a .NET project.
This abstraction allows your launch profiles to be agnostic of infrastructure and geared more toward intention (e.g., "run my app inside a container" vs. "run using the built-in server").

3. applicationUrl

This element defines the network bindings for the application during development. It tells the development host (like Kestrel) which ports and protocols (HTTP/HTTPS) the application should listen on.

The presence of both HTTP and HTTPS reflects:
  • A need for secure local testing
  • Compatibility with different local service consumers
  • Simulation of real-world hosting conditions

4. launchBrowser & launchUrl

These two elements describe the startup behavior of your development session:
  • launchBrowser specifies whether to automatically open a browser.
  • launchUrl defines the path or endpoint that the browser should navigate to after the app starts.
This abstracts the idea of launching your app into a specific state — such as the Swagger UI for APIs — giving you control over the first interaction with your running application.

5. environmentVariables

Environment variables represent runtime configuration values that are injected into the app process when launched.

From a theoretical view:
  • They enable environment-specific behaviors (e.g., showing debug info in Development mode).
  • They act as a loose coupling mechanism, allowing the app to adapt its behavior based on externalized values.
  • The primary variable you’ll often set is ASPNETCORE_ENVIRONMENT, which the ASP.NET Core framework uses to determine which appsettings.{Environment}.json file to load.
This section empowers you to simulate real-world deployment behaviors without altering code or core config files.

6. dotnetRunMessages

This optional flag enables diagnostic verbosity during command-line execution. It provides insight into listening addresses, host readiness, and runtime logs useful during CLI-based workflows.

Theoretically, this enhances developer observability during local execution and supports script-driven environments (CI/CD pipelines, custom launch scripts).

Bonus: Docker Launch Profile (Optional)
If you're using Docker, Visual Studio may add a profile like this:
"Docker": {
  "commandName": "Docker",
  "launchBrowser": true,
  "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger"
}

The {Scheme}, {ServiceHost}, and {ServicePort} are dynamically replaced during container startup.

Summary

You can think of launchSettings.json as your local run configuration manager. It lets you:
  • Control how your app launches (Kestrel, IIS Express, Docker)
  • Set URLs, ports, and environments
  • Auto-launch your browser to specific routes
  • Inject custom environment variables for development
  • Keep multiple profiles for different test and debug scenarios
Once you get comfortable with its structure, you’ll find it much easier to control and optimize your development setup.

Why Kestrel is Used Behind Nginx or IIS in ASP.NET Core?

When developing and deploying web applications using ASP.NET Core, the default web server used is Kestrel — a high-performance, cross-platform web server built by Microsoft. While Kestrel is powerful and fast, it is often not recommended to expose it directly to the internet in production. Instead, it’s commonly used behind a reverse proxy server like Nginx (Linux) or IIS (Windows).

But why is that necessary? In this article, we’ll explore the reasons behind this practice, how reverse proxies work, and how they improve the security, scalability, and reliability of your ASP.NET Core applications.

What is Kestrel Server?

Kestrel is the default web server used by ASP.NET Core applications. It is a cross-platform, high-performance, and lightweight HTTP server built on top of libuv (in earlier versions) and now uses managed sockets in newer .NET versions. Kestrel is responsible for handling HTTP requests and forwarding them to the ASP.NET Core middleware pipeline for processing.

Kestrel supports key features like HTTPS, HTTP/2, and WebSockets, and can be run in two ways:
  • Standalone (directly exposed to the internet, suitable for internal services or development)
  • Behind a reverse proxy like Nginx (Linux) or IIS (Windows), which is recommended for production environments for better security, SSL termination, and static content handling.

Thanks to its asynchronous architecture, Kestrel can handle thousands of concurrent connections efficiently, making it ideal for modern web applications and APIs.

However, while Kestrel is excellent for handling application-level logic, it lacks some advanced features that full-fledged web servers like Nginx or IIS provide, particularly in edge-facing, production-grade deployments.

What is a Reverse Proxy?

A reverse proxy is a server that sits between client devices and backend servers, forwarding incoming requests to one or more internal servers and then returning the server's response to the client.
In simple terms, the client interacts with the reverse proxy, not directly with your application server.

How It Works:
Client  Reverse Proxy (e.g., Nginx/IIS)  Backend Server (e.g., Kestrel)

When a user visits your website:
1. The request goes to the reverse proxy.
2. The proxy server forwards the request to the actual application server.
3. The application processes it and returns the result to the proxy, which then delivers it to the user.

Benefits of Using a Reverse Proxy:

  • Improved security (hides your backend server)
  • SSL termination (handles HTTPS at the edge)
  • Load balancing (distributes traffic across multiple servers)
  • Caching and compression for static files
  • Request filtering and rate limiting
In production, Kestrel (the ASP.NET Core server) is often placed behind a reverse proxy like:
  • Nginx (on Linux)
  • IIS (on Windows)
This setup enhances security, performance, and scalability while letting Kestrel focus on running your app logic.

This architecture adds a layer of control and protection between the external internet and your application logic.

Why Use Kestrel Behind Nginx or IIS?

In production environments, Kestrel is typically used behind a reverse proxy like Nginx (Linux) or IIS (Windows) because, while Kestrel is a fast and lightweight web server, it lacks certain edge-facing features needed for robust, secure deployments.

1. Security

Exposing Kestrel directly to the internet can be risky. It does not have built-in protections like:

  • Request filtering
  • IP blocking
  • Rate limiting
  • Header manipulation

Using a reverse proxy like Nginx or IIS allows you to enforce security policies before requests reach your application.

Example: You can use Nginx to block access to certain IP ranges or enforce HTTPS:

server {
    listen 443 ssl;
    server_name myapp.com;
    ssl_certificate /etc/ssl/certs/myapp.crt;
    ssl_certificate_key /etc/ssl/private/myapp.key;

    location / {
        proxy_pass http://localhost:5000;
    }
}

listen 443 ssl;
  • Tells Nginx to listen on port 443, the default port for HTTPS.
  • The ssl directive enables SSL/TLS support on this port.
server_name myapp.com;
  • Specifies the domain name (or hostname) this configuration applies to.
  • When users browse to https://myapp.com, Nginx knows to use this block.
ssl_certificate /etc/ssl/certs/myapp.crt;
  • Points to the SSL certificate file (public key) for your domain.
  • This is what browsers use to verify that the site is secure and trusted.
ssl_certificate_key /etc/ssl/private/myapp.key;
  • Points to the private key for the certificate.
  • It is used by the server to establish secure (encrypted) connections.

2. TLS Termination (HTTPS Support)

Handling SSL/TLS certificates and encryption can be offloaded to the reverse proxy, reducing overhead on your app.
  • Kestrel supports HTTPS, but managing certificates and security policies is easier with IIS or Nginx.
  • This also helps when you want to use Let's Encrypt with automatic renewal via Nginx.

3. Static File Handling

Web servers like Nginx and IIS are optimized for serving static assets (CSS, JS, images) quickly. Kestrel can serve static files, but it's not as efficient.
Offloading static content to a reverse proxy reduces load on your app and improves performance.

4. Load Balancing and Scalability

Reverse proxies can distribute traffic to multiple instances of your app, improving scalability and availability.
Example: You can set up Nginx to round-robin requests across multiple Kestrel instances:
upstream myappcluster {
    server 127.0.0.1:5000;
    server 127.0.0.1:5001;
}

server {
    listen 80;

    location / {
        proxy_pass http://myappcluster;
    }
}

5. Advanced Features in IIS

If you're deploying on Windows, using IIS as a reverse proxy enables enterprise-grade features such as:
  • Windows Authentication (NTLM/Kerberos)
  • Centralized logging
  • URL rewriting
  • Application pool isolation
In such scenarios, IIS handles incoming requests and forwards them to the ASP.NET Core application running on Kestrel, using the ASP.NET Core Module (ANCM).

6. Better Error Handling and Logging

Reverse proxies can handle and log requests that never reach your application, such as malformed or malicious ones. They can also return custom error pages for 404s or 500s.

Example: ASP.NET Core Behind Nginx on Linux.

You have an ASP.NET Core application running on Kestrel (e.g., localhost:5000), and you want to serve it via Nginx with HTTPS enabled at https://myapp.com.

Step-by-Step Guide.

Step 1: Publish Your ASP.NET Core App
On your development machine:
dotnet publish -c Release -o /var/www/myapp
Copy the published folder to your Linux server (using SCP, SFTP, etc.).

Step 2: Install .NET Runtime on the Server
On Ubuntu:
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y aspnetcore-runtime-7.0

Step 3: Create a Systemd Service for Kestrel
Create a file: /etc/systemd/system/myapp.service
[Unit]
Description=My ASP.NET Core App
After=network.target

[Service]
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/dotnet /var/www/myapp/MyApp.dll
Restart=always
RestartSec=10
SyslogIdentifier=myapp
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target
Then start and enable it:
sudo systemctl daemon-reexec
sudo systemctl start myapp
sudo systemctl enable myapp
Kestrel will now run your app on localhost:5000.

Step 4: Install Nginx and SSL
sudo apt update
sudo apt install nginx
To set up HTTPS with Let’s Encrypt:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d myapp.com

Step 5: Configure Nginx as a Reverse Proxy
Edit or create a file:
/etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name myapp.com;

    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
Enable the config:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Optional: Add this block to redirect all HTTP traffic to HTTPS.
server {
    listen 80;
    server_name myapp.com;
    return 301 https://$host$request_uri;
}

Final Flow.
Client (HTTPS)
     
 Nginx (port 443, SSL)
     
Kestrel (localhost:5000, HTTP)
     
ASP.NET Core App

Now, users interact with Nginx, and Kestrel handles only the application logic — securely and efficiently.

Summary

Kestrel is a fast and reliable web server designed for ASP.NET Core, but it lacks certain edge-facing capabilities required in real-world production deployments. That’s why it’s commonly used behind a reverse proxy like Nginx (Linux) or IIS (Windows). These proxy servers handle critical tasks like HTTPS, security filtering, load balancing, and static content delivery, allowing Kestrel to focus purely on application logic.

Using this layered architecture ensures security, performance, scalability, and maintainability of ASP.NET Core applications in production.

HTTP Status Code: 101 Switching Protocols.

When interacting with the web, we often come across common HTTP status codes like 200 OK, 404 Not Found, or 500 Internal Server Error. But there are many lesser-known yet important codes, such as HTTP Status Code 101 – Switching Protocols. In this article, we’ll explore what this status code means, when it's used, and why it's important in modern web applications.

What is the 101 HTTP Status Code?

The HTTP status code 101 Switching Protocols is part of the 1xx series, indicating an informational response from the server. It is utilized when the server agrees to upgrade its protocol and is ready to switch to a different protocol specified in the client's request. This status code is commonly associated with the WebSocket protocol, which allows for full-duplex communication channels over a single TCP connection.

Conditions for Receiving 101 Switching Protocols.

The HTTP status code 101 Switching Protocols is received under specific conditions when a client sends a request with the intention of switching to a different protocol. Here are the conditions for receiving the 101 Switching Protocols status:
  • Upgrade Request Header: The client sends a request with an Upgrade header, indicating the desire to switch protocols. This header specifies the protocol the client wants to switch to.
  • Server Agreement: The server supports the requested protocol and is willing to switch. The server includes the Upgrade header in its response to acknowledge the protocol switch.

How to Handle 101 Switching Protocols?

Client's Upgrade Request: The client sends an initial request to the server, specifying the desired protocol in the Upgrade header.
GET /example HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade

Server Acknowledgment (101 Switching Protocols): If the server supports the requested protocol, it responds with a 101 Switching Protocols status.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade

Switching Protocols: Both the client and server switch to the agreed-upon protocol. Subsequent communication follows the rules and specifications of the newly established protocol.

In this example, the client requests to upgrade the protocol to WebSocket by including the Upgrade: websocket and Connection: Upgrade headers. The server, supporting WebSocket, responds with a 101 Switching Protocols status, acknowledging the switch. Subsequently, both the client and server switch to the WebSocket protocol for further communication.

Use Cases:
  • The most common use case for 101 Switching Protocols is during the establishment of WebSocket connections.
  • It can be employed for other scenarios where the client and server agree to switch to a different protocol for enhanced communication.

When You Don't See It

You won’t typically see 101 Switching Protocols in a browser or developer console unless you’re specifically working with protocol upgrades like WebSockets.

It’s a behind-the-scenes part of setting up persistent, real-time connections.

Conclusion.

HTTP status code 101 Switching Protocols serves as an indicator that the server agrees to upgrade its protocol based on the client's request. This is particularly significant in scenarios like WebSocket communication, providing a seamless transition to a different protocol for enhanced and real-time interaction between clients and servers.

Understanding Servers in ASP.NET Core.

In ASP.NET Core, a server is a critical component responsible for listening to incoming HTTP requests, processing them, and then returning appropriate responses. It acts as the bridge between the outside world (browsers, mobile apps, API consumers) and your ASP.NET Core application.


When you build a web application using ASP.NET Core, your application doesn't just sit there waiting; it needs to run inside a web server environment like Kestrel, IIS, or HTTP.sys that continuously listens for incoming network requests.


ASP.NET Core applications are self-hosted, meaning they don’t rely on the legacy IIS pipeline. Instead, they can run on any server that can host a .NET Core process. This cross-platform model allows the application to be hosted on Windows, Linux, or macOS, making ASP.NET Core truly modern and flexible.

What is a Server in ASP.NET Core?

In ASP.NET Core, a server is a component responsible for:

  • Listening for HTTP requests
  • Forwarding Requests to the Application Pipeline
  • Returning HTTP responses to the client
  • Handling Protocols and Security
  • Logging, Monitoring, and Resource Management

Unlike the traditional ASP.NET (pre-Core), which is tightly integrated with IIS, ASP.NET Core is self-hosted, meaning it can run independently of IIS and on any platform (Windows, Linux, macOS). This makes it ideal for cloud-native applications and containerized deployments.

Types of Servers in ASP.NET Core.

One of its biggest strengths of ASP.NET Core is its flexible hosting model, which allows developers to choose how their apps are hosted and served.

When it comes to hosting an ASP.NET Core application, you have three primary server options:

  • Kestrel
  • IIS (Internet Information Services)
  • HTTP.sys

Let’s dive into each one in detail.

1. Kestrel Server (Default and Cross-platform)

Kestrel is the default web server included with ASP.NET Core. It’s a lightweight, cross-platform, high-performance web server designed to serve ASP.NET Core applications either directly or behind a reverse proxy (like Nginx or IIS).

Features:

  • Supports HTTP/1.1, HTTP/2, and HTTPS
  • Fully asynchronous I/O for better scalability
  • Works on all platforms (Windows, Linux, macOS)
  • Designed to be fast and minimal
  • Handles WebSockets

Configuration Example for Kestrel Server. (Program.cs in .NET 6+)

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.Limits.MaxRequestBodySize = 10 * 1024; // 10 KB
    serverOptions.ListenAnyIP(5001); // HTTP
    serverOptions.ListenAnyIP(5002, listenOptions =>
    {
        listenOptions.UseHttps(); // HTTPS
    });
});

var app = builder.Build();
app.Run();
Kestrel is Ideal for running web apps and APIs in Docker, Kubernetes, or Linux environments. Commonly used behind Nginx or IIS in production. 

In production-grade ASP.NET Core deployments, developers don’t expose the Kestrel server directly to the internet. Instead, they use a more mature and robust reverse proxy server like Nginx (on Linux) or IIS (on Windows) in front of the Kestrel server. This setup has several benefits related to security, performance, and scalability.

2. IIS (Internet Information Services)

IIS (Internet Information Services) is a powerful, flexible, and secure web server developed by Microsoft for hosting web applications on the Windows platform. In the context of ASP.NET Core, IIS no longer runs your application directly as it did in the older .NET Framework. Instead, it acts as a reverse proxy server that forwards HTTP requests to the Kestrel server, which is the actual web server running the ASP.NET Core application.

When hosting an ASP.NET Core application with IIS, a special component called the ASP.NET Core Module (ANCM) comes into play. This module is installed as part of the .NET Hosting Bundle and is responsible for starting the application and routing all incoming HTTP traffic from IIS to the internal Kestrel process. This design ensures that IIS can still provide enterprise-grade features like Windows Authentication, URL rewriting, SSL termination, application pool isolation, and centralized logging, while leveraging Kestrel’s performance and cross-platform benefits in the background.

IIS supports two hosting models for ASP.NET Core applications: in-process and out-of-process. In in-process hosting, the application runs within the IIS worker process (w3wp.exe), providing better performance and lower overhead. This is the recommended and default mode since ASP.NET Core 2.2. On the other hand, out-of-process hosting runs the application as an external process (using dotnet MyApp.dll), and IIS simply forwards requests to it. While still functional, this mode introduces an extra communication layer and is less efficient compared to in-process hosting.

Configuration of IIS in ASP.NET Core.

To configure IIS for an ASP.NET Core application, you need to install the .NET Core Hosting Bundle on your Windows server, publish your application, and set up a website in IIS that points to the published folder. 

IIS acts as a reverse proxy, forwarding requests to the Kestrel server via the ASP.NET Core Module, using the settings defined in the web.config file. This allows your ASP.NET Core app to run smoothly on IIS while benefiting from features like Windows Authentication, SSL termination, and centralized management.

<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="dotnet" arguments="MyApp.dll" hostingModel="inprocess" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" />
  </system.webServer>
</configuration>

3. HTTP.sys Server (Windows-only Alternative)

HTTP.sys is a Windows-only web server that ASP.NET Core can use as an alternative to Kestrel. It’s built on the Windows kernel-mode HTTP.sys driver, which offers advanced features like Windows Authentication (NTLM/Kerberos), SSL termination, port sharing, and request queuing. Unlike Kestrel, it doesn't require a reverse proxy (like IIS or Nginx) and can handle HTTP requests directly. HTTP.sys is ideal for intranet applications or services that need deep Windows integration without the overhead of IIS.

Configuration Example of HTTP.sys.

builder.WebHost.UseHttpSys(options =>
{
    options.Authentication.Schemes = AuthenticationSchemes.NTLM;
    options.UrlPrefixes.Add("http://localhost:5000");
});

How to choose the right server?

Below are some popular use cases and server recommendations that you can follow for choosing the right server for your ASP.NET Core application:
Deployment Scenario Recommended Server
Cross-platform deployments Kestrel
Windows enterprise environments IIS (with Kestrel)
Windows-only services HTTP.sys
Containerized environments Kestrel + Nginx
Lightweight API backend Kestrel

Conclusion

Understanding how servers work in ASP.NET Core is crucial for building reliable, high-performance web applications. Whether you're deploying on Windows with IIS or on Linux with Kestrel and Nginx, ASP.NET Core provides the flexibility and control to choose the right server architecture for your application.

Key Takeaways:
  • Kestrel is the default, cross-platform server.
  • IIS and HTTP.sys are Windows-specific options.
  • Use reverse proxies for better security and performance.
  • Server configuration affects scalability, security, and performance.

DON'T MISS

Tech News
© all rights reserved
made with by AlgoLesson