European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Core 10.0 Hosting - HostForLIFE :: How to Use ASP.NET Core Web API API Versioning?

clock April 14, 2026 07:35 by author Peter

Your ASP.NET Core Web API will change over time as you develop it. You can enhance current endpoints, modify answer formats, or add new functionalities. However, what happens to current users who have already made use of your API? API versioning becomes crucial in this situation.

By maintaining different versions of your API, you can enable new clients to utilize current features while maintaining the functionality of older clients. This post will teach you a straightforward, useful, and methodical approach to implementing API versioning in ASP.NET Core Web API.

What is versioning of an API?
One method that enables many versions of your API to exist simultaneously is called API versioning.

To put it simply:

  • Version 1 is still being used by older users.
  • Version 2 is available to new users.
  • Your program is still reliable and compatible with older versions.

In real-world systems, where disruptive changes can impact thousands of users, this is crucial.

Why API Versioning is Important
API versioning helps you:

  1. Avoid breaking existing clients
  2. Introduce new features safely
  3. Maintain backward compatibility
  4. Manage API lifecycle effectively

Without versioning, even small changes can break applications that depend on your API.

Types of API Versioning in ASP.NET Core
There are multiple ways to implement API versioning:

  • URL Versioning (most common)
  • Query String Versioning
  • Header Versioning
  • Media Type Versioning

Let’s understand each one in simple terms.

URL Versioning

Version is included in the URL.

Example:
/api/v1/products
/api/v2/products


This is the easiest and most widely used approach.

Query String Versioning

Version is passed as a query parameter.

Example:
/api/products?version=1

Header Versioning

Version is passed in request headers.

Example:
api-version: 1

Media Type Versioning
Version is specified in the Accept header.

Example:
application/json;v=1

Prerequisites
Before starting, ensure you have:

  • ASP.NET Core Web API project
  • .NET SDK installed
  • Basic understanding of controllers and routing

Step 1: Install API Versioning Package
Run the following command:
dotnet add package Microsoft.AspNetCore.Mvc.Versioning

This package provides built-in support for API versioning.

Step 2: Configure API Versioning in Program.cs

Open your Program.cs file and add the following configuration:
builder.Services.AddApiVersioning(options =>
{
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.ReportApiVersions = true;
});


Explanation:

  1. AssumeDefaultVersionWhenUnspecified → Uses default version if not provided
  2. DefaultApiVersion → Sets default version
  3. ReportApiVersions → Returns supported versions in response headers

Step 3: Add Versioning to Controller
Now, define API version in your controller.
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("Products from API Version 1");
    }
}


This controller handles version 1 of the API.

Step 4: Create Version 2 of API
Now, let’s create a second version.
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("2.0")]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("Products from API Version 2 with new features");
    }
}


Now you have two versions running side by side.

Step 5: Using Multiple Versions in Same Controller
You can also support multiple versions in a single controller.
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class OrdersController : ControllerBase
{
    [HttpGet]
    [MapToApiVersion("1.0")]
    public IActionResult GetV1()
    {
        return Ok("Orders from Version 1");
    }

    [HttpGet]
    [MapToApiVersion("2.0")]
    public IActionResult GetV2()
    {
        return Ok("Orders from Version 2");
    }
}


This helps reduce code duplication.

Step 6: Configure Query String Versioning

If you want to use query string versioning:
options.ApiVersionReader = new QueryStringApiVersionReader("version");

Now API can be called like:
/api/products?version=1

Step 7: Configure Header Versioning
options.ApiVersionReader = new HeaderApiVersionReader("api-version");

Request example:
api-version: 1

Step 8: Best Practices for API Versioning
Follow these best practices:

  • Use clear version naming (v1, v2)
  • Avoid breaking changes in existing versions
  • Deprecate old versions gradually
  • Document all versions properly
  • Use URL versioning for simplicity

Step 9: Real-World Example
Imagine an e-commerce API:
Version 1:

  • Returns product name and price

Version 2:

  • Adds product description and category
  • Old apps continue using v1, while new apps use v2.
  • This ensures smooth upgrades without breaking existing users.

Advantages of API Versioning

  • Better maintainability
  • Smooth upgrades
  • Improved developer experience
  • Backward compatibility

Summary
Building scalable and future-proof apps requires the use of ASP.NET Core Web API versioning. It enables you to implement changes without upsetting current customers. You may simply manage different API versions using URL, query string, or headers by utilizing built-in versioning functionality. As your API develops, adhering to best practices guarantees that it will continue to be dependable, adaptable, and simple to maintain.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: How to Use the Outbox Pattern for Microservices in .NET?

clock April 10, 2026 09:05 by author Peter

Ensuring dependable message delivery across services is one of the largest issues developers encounter in contemporary microservices architecture using.NET and ASP.NET Core. There is always a chance of failure when your application needs to send a message (for instance, to a message broker like Kafka or RabbitMQ) in addition to performing a database operation.

 

For example:

  • The database stores the data.
  • However, the message is not published.

Data inconsistency results from this, which is a major issue in distributed systems.

We employ the Outbox Pattern in.NET microservices to address this problem.

This post will explain the Outbox Pattern in layman's terms and show us how to use ASP.NET Core and Entity Framework Core to implement it step-by-step.

What is the Outbox Pattern?
The Outbox Pattern is a design pattern used to ensure that database changes and messages are saved together reliably.

In simple words
Instead of sending messages directly:

  • Save the message in a database table (Outbox table)
  • Later, a background service reads and publishes it

This ensures:

  • No message is lost
  • Data consistency is maintained

Why Do We Need the Outbox Pattern?
In a typical microservices system:

  • You update your database
  • Then you publish an event

But what if:

  • Database save succeeds
  • Message publishing fails?
  • This creates inconsistency.

The Outbox Pattern solves this by:

  1. Storing both data and message in the same transaction
  2. Publishing messages later safely

Real-Life Example
Imagine an e-commerce system:

  • Order is placed
  • Database is updated
  • Event "OrderCreated" should be sent

Without Outbox:
If event fails → other services never know about the order

With Outbox:

  • Event is stored in DB
  • It will be sent eventually

How Outbox Pattern Works
The flow is simple:

  • Application saves business data
  • Application also saves event in Outbox table
  • Both operations happen in a single transaction
  • Background worker reads Outbox table
  • Publishes messages to message broker
  • Marks message as processed

This guarantees eventual consistency in distributed systems.

Step 1: Create Outbox Table

First, create an Outbox entity.
public class OutboxMessage
{
    public Guid Id { get; set; }
    public string Type { get; set; }
    public string Payload { get; set; }
    public DateTime CreatedAt { get; set; }
    public bool Processed { get; set; }
}


Add it to DbContext:
public DbSet<OutboxMessage> OutboxMessages { get; set; }

Step 2: Save Data and Event Together
When saving business data, also save the event.
public async Task CreateOrder(Order order)
{
    _context.Orders.Add(order);

    var message = new OutboxMessage
    {
        Id = Guid.NewGuid(),
        Type = "OrderCreated",
        Payload = JsonSerializer.Serialize(order),
        CreatedAt = DateTime.UtcNow,
        Processed = false
    };

    _context.OutboxMessages.Add(message);

    await _context.SaveChangesAsync();
}

Key point
Both operations happen in one transaction, ensuring reliability.

Step 3: Create Background Service to Process Outbox
Now create a background worker.
public class OutboxProcessor : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;

    public OutboxProcessor(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using var scope = _serviceProvider.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();

            var messages = await context.OutboxMessages
                .Where(x => !x.Processed)
                .ToListAsync();

            foreach (var message in messages)
            {
                // Publish message (simulate)
                Console.WriteLine($"Publishing: {message.Type}");

                message.Processed = true;
            }

            await context.SaveChangesAsync();

            await Task.Delay(5000);
        }
    }
}

Step 4: Register Background Service
builder.Services.AddHostedService<OutboxProcessor>();

Step 5: Publish Message to Broker (Optional)
Instead of Console.WriteLine, integrate with:

  • RabbitMQ
  • Kafka
  • Azure Service Bus

Example:
await _messageBus.PublishAsync(message.Payload);

Handling Failures and Retries

To make the system robust:

  • Retry failed messages
  • Use exponential backoff
  • Log errors
  • Avoid infinite retries

Add fields like:
public int RetryCount { get; set; }
public string Error { get; set; }

Benefits of Outbox Pattern in .NET

  • Reliable message delivery
  • Prevent data inconsistency
  • Supports eventual consistency
  • Works well with microservices
  • Improves system resilience

Common Challenges

  • Table growth (Outbox table can grow large)
  • Need cleanup strategy
  • Slight delay in message delivery

Best Practices

  • Use batching for processing messages
  • Clean processed messages regularly
  • Use indexing for performance
  • Keep payload small
  • Use JSON serialization carefully

Real-World Use Case

In a payment system:

  • Payment is processed
  • Event is stored in Outbox
  • Notification service receives even

Even if messaging fails initially, it will retry and succeed.

Summary
The Outbox Pattern in .NET microservices is a powerful technique to ensure reliable message delivery and maintain data consistency across distributed systems. By storing events in a database table and processing them asynchronously using a background service, you can avoid message loss and build resilient, scalable applications. This pattern is essential for modern ASP.NET Core microservices that rely on event-driven architecture and message brokers.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: An Introduction to Authentication and Authorization in Contemporary Applications

clock April 1, 2026 08:42 by author Peter

Privacy has never been a choice. Parts of your identification, like your name, email address, and occasionally even your location or payment information, are shared each time you use a service, order food, or log into an app. However, when we click "Login," we typically don't give much thought to what goes on behind the scenes.

Authorization vs. Authentication: The Most Perplexing Ideas
This is still best illustrated by a straightforward real-world example: picture yourself entering a hotel.

They verify your reservation and verify your identity at the front desk. That is authentication, or demonstrating that you are who you say you are.

Now picture yourself attempting to enter a restricted location like the VIP lounge. You might not be permitted entry even if you are a visitor. Authorization is the process of determining what you are permitted to do.

Even now, a lot of systems fail due to poorly designed authorization rather than insufficient authentication.

How We Used to Do It (and Why It Changed)
A few years ago, most applications relied heavily on session-based authentication.
You logged in with a username and password. The server stored your session. Every request depended on that session being valid.

That worked well for simple applications, but it didn't scale well for:

  • Mobile apps
  • Microservices
  • Distributed systems
  • APIs

This is where token-based authentication became the standard.

Tokens: Your Digital Identity Card
Think of a token as a digital ID card.
Instead of asking the server "who are you?" on every request, you just present your token.
The server trusts the token and allows or denies access based on what's inside it.

What is a JWT?

A JWT (JSON Web Token) is a compact, secure way to transmit information between systems.

But here's an important correction from older explanations:

  • A JWT is not inherently secure by itself
  • It is signed (and sometimes encrypted) to ensure integrity

You can think of it as a sealed envelope:

  • Anyone can read it (unless encrypted)
  • But no one can tamper with it without breaking the seal

JWT Structure (Still the Same, Still Important)
A JWT has three parts:
Header
Contains metadata like the signing algorithm (e.g., HS256, RS256)

Payload
Contains claims (data about the user)

Common claims include:

  • sub: user identifier
  • iss: issuer (who created the token)
  • aud: audience (who the token is for)
  • exp: expiration time

Signature
Ensures the token hasn't been modified
One important clarification: The signing algorithm is defined in the Header, not the Signature

OAuth2 and OpenID Connect
OAuth2
OAuth2 is not an authentication protocol.

It is an authorization framework that allows one application to access resources from another on behalf of a user.

Example:
When you click "Login with Google", your app does NOT get your password.

Instead:

  • Google authenticates you
  • Google gives your app a token
  • Your app uses that token to access limited user data

So OAuth2 is about: delegating access, not identifying the user

OpenID Connect (OIDC)

OpenID Connect sits on top of OAuth2 and adds authentication.
It introduces the concept of an ID Token, which is usually a JWT.
This ID token tells your application who the user is

So in modern systems:

  • OAuth2 : authorization (access to resources)
  • OIDC : authentication (identity)
  • Common Mistakes (Still Happening Today)

Even in modern systems, developers still fall into these traps:

1. Putting sensitive data in JWT payload
JWTs are not encrypted by default. Never store passwords or secrets.

2. Not validating tokens properly
Always validate:

  • Signature
  • Expiration
  • Issuer
  • Audience

3. Long-lived tokens
Short-lived access tokens + refresh tokens are the safer approach.

ASP.NET Core Identity
ASP.NET Core Identity is the default membership system provided by Microsoft. It handles everything related to user management.

  • User registration and login
  • Password hashing (secure by default)
  • Roles and claims
  • Token generation

For APIs and modern apps, JWT authentication is the standard.

Instead of sessions, you issue a token after login.

Basic JWT Setup
builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,

            ValidIssuer = "test-app",
            ValidAudience = "test-app",
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes("your-secret-key"))
        };
    });


Authorization (Roles, Claims, Policies)
As mentioned before, authentication tells you who the user is, but authorization defines what they can do.

Role-based authorization

[Authorize(Roles = "Admin")]
public IActionResult AdminOnly()
{
    return Ok("Admin access");
}

Claims-based authorization
[Authorize(Policy = "CanEdit")]
public IActionResult Edit()
{
    return Ok();
}

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("CanEdit", policy =>
        policy.RequireClaim("permission", "edit"));
});


In modern systems, claims-based or policy-based authorization is preferred over simple roles because it’s more flexible. ASP.NET Core Identity is an interesting topic that i will share about more videos and tutorials for better understanding how it works in the future.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Month List

Tag cloud

Sign in