← Back to Article List         
API Versioning in ASP.NET Core

API Versioning in ASP.NET Core

Published on 15 Jun 2026     21 min read .Net
Web API API Versioning

What is API Versioning?

API versioning means creating different versions of an API so that changes don’t break existing users.

API versioning = updating your API without breaking old users

Why API Versioning is needed

When you update an API:

  • Old apps may stop working
  • Users may get errors

So instead of changing the old API, you create a new version.

API Versioning Dependencies in .NET (ASP.NET Core)

To implement API versioning in ASP.NET Core, you mainly need these NuGet packages:

1. Required Package

  • Asp.Versioning.Mvc

This is the core package that enables API versioning.

2. Optional (but recommended)

  • Asp.Versioning.Mvc.ApiExplorer

Used for:

  • Swagger integration
  • Viewing versioned APIs clearly

Installation Commands

Using .NET CLI:

dotnet add package Asp.Versioning.Mvc
dotnet add package Asp.Versioning.Mvc.ApiExplorer
dotnet add package Swashbuckle.AspNetCore

Simple Summary

Package

Purpose

Asp.Versioning.Mvc

Core API versioning

Asp.Versioning.Mvc.ApiExplorer

Supports Swagger/version discovery

Swashbuckle.AspNetCore

Swagger UI

 

You must install the first package, others depend on your needs (especially Swagger).

Types of API Versioning in .NET (ASP.NET Core)

In ASP.NET Core (using
Microsoft.AspNetCore.Mvc.Versioning), you can version APIs in a few common ways.

1. URL Path Versioning (Most Common)

Version is included in the URL.

/api/v1/users
/api/v2/users

Pros

  • Easy to understand
  • Simple to test

Cons

  • URL changes for every version

2. Query String Versioning

Version is passed as a query parameter.

/api/users?api-version=1.0

Pros

  • Same URL structure
  • Easy to try in browser

Cons

  • Less clean than URL versioning

3. Header Versioning

Version is sent in request headers.

api-version: 1.0

Pros

  • Clean URLs
  • Good for enterprise APIs

Cons

  • Harder to test manually

4. Media Type (Content Negotiation) Versioning

Version is passed in the Accept header.

Accept: application/json;v=1.0

Pros

  • Very flexible
  • Keeps URL clean

Cons

  • More complex
  • Not beginner-friendly

5. Namespace Versioning (Code-level)

Different versions are separated using namespaces.

Controllers.V1
Controllers.V2

Pros

  • Clean code organization
  • Easy to maintain

Cons

  • Not visible to API users directly

Simple Summary

Type

Where version is placed

URL Path

In URL (/v1/)

Query String

In query (?api-version=1)

Header

In request header

Media Type

In Accept header

Namespace

In code structure


Key Point

URL versioning is the most commonly used and easiest to understand.

Project Structure (Versioning with Different Folders & Namespaces)

Controllers
 └── v1
      └── WeatherForecastController.cs

 └── v2
      └── WeatherForecastController.cs

This is a clean enterprise-style API versioning approach.

  • Each version has:
    • Separate folder
    • Separate namespace
    • Separate controller implementation

·         You can support:

Version

URL

Old clients (V1)

/api/weatherforecast

New clients (V2)

/api/v2/weatherforecast

 


1. Install Required Package

dotnet add package Asp.Versioning.Mvc

Program.cs

using Asp.Versioning;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddApiVersioning(options =>
{
   options.DefaultApiVersion = new ApiVersion(1, 0);
   // If version not specified -> use V1
   options.AssumeDefaultVersionWhenUnspecified = true;
   options.ReportApiVersions = true;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
   app.UseSwagger();
   app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

Folder Structure

Controllers
 
── v1
     └── WeatherForecastController.cs
 
 └── v2
      └── WeatherForecastController.cs

V1 Controller

Controllers/v1/WeatherForecastController.cs

using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;

namespace WebAPIVersioning.Controllers.v1
{
    [ApiController]

    [ApiVersion("1.0")]

    // Old route (without version)
    [Route("api/[controller]")]

    // Optional: also support /api/v1/weatherforecast
    [Route("api/v{version:apiVersion}/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            return Ok(new
            {
                Version = "V1",
                Message = "Old Client API"
            });
        }
    }
}

V2 Controller

Controllers/v2/WeatherForecastController.cs

using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;

namespace WebAPIVersioning.Controllers.v2
{
    [ApiController]

    [ApiVersion("2.0")]

    [Route("api/v{version:apiVersion}/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            return Ok(new
            {
                Version = "V2",
                Message = "New Version API"
            });
        }
    }
}

Working Endpoints

URL

Version

/api/weatherforecast

V1

/api/v1/weatherforecast

V1

/api/v2/weatherforecast

V2

How it works

This line:

options.AssumeDefaultVersionWhenUnspecified = true;

means:

If client does not send version,
automatically use default version (V1).

Best Practice

This approach is ideal when:

  • Existing production clients already use unversioned URLs
  • You cannot break old applications
  • You want gradual migration to versioned APIs

Recommended Migration Strategy

Stage

URL

Existing system

/api/weatherforecast

Introduce V2

/api/v2/weatherforecast

Future migration

Encourage clients to move to /api/v2/...

Later

Deprecate old route

Optional: Mark V1 as Deprecated

[ApiVersion("1.0", Deprecated = true)]

Then response headers will indicate:

api-deprecated-versions: 1.0

Key Points

Feature

Explanation

Separate folders

Controllers/v1 and Controllers/v2

Separate namespaces

Controllers.v1 and Controllers.v2

Same controller name

Allowed because namespace differs

Same endpoint name

Differentiated using API version

Backward compatibility

Old clients can still use v1

Single Controller Versioning (Same Namespace)

In this approach:

  • Only ONE controller
  • Same namespace
  • Multiple API versions inside same controller

·         Old clients continue using:

/api/weatherforecast

·         New clients use:

/api/v2/weatherforecast

Program.cs

using Asp.Versioning;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddApiVersioning(options =>
{
    // Default Version
    options.DefaultApiVersion = new ApiVersion(
1, 0);

    // If no version specified -> use V1
    options.AssumeDefaultVersionWhenUnspecified =
true;

    // Shows supported versions in headers
    options.ReportApiVersions =
true;
});

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();

    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Controller

Controllers/WeatherForecastController.cs

using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;

namespace WebAPIVersioning.Controllers
{
    [ApiController]

    // Supported versions
    [ApiVersion("1.0")]
    [ApiVersion("2.0")]

    // Old route
    [Route("api/[controller]")]

    // Versioned route
    [Route("api/v{version:apiVersion}/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        // ---------------- V1 ----------------

        [HttpGet]

        [MapToApiVersion("1.0")]
        public IActionResult GetV1()
        {
            return Ok(new
            {
                Version = "V1",
                Message = "Old Client API Response"
            });
        }

        // ---------------- V2 ----------------

        [HttpGet]

        [MapToApiVersion("2.0")]
        public IActionResult GetV2()
        {
            return Ok(new
            {
                Version = "V2",
                Message = "New API Response"
            });
        }
    }
}

Working Endpoints

URL

Version

Method

/api/weatherforecast

V1

GetV1()

/api/v1/weatherforecast

V1

GetV1()

/api/v2/weatherforecast

V2

GetV2()

How Version Resolution Works

Case 1

GET /api/weatherforecast

No version specified.

Because of:

options.AssumeDefaultVersionWhenUnspecified = true;

ASP.NET automatically uses:

Version 1.0

So:

GetV1()

executes.

Case 2

GET /api/v2/weatherforecast

Route contains:

v2

So:

GetV2()

executes.

Important Concept

Even though both methods use:

[HttpGet]

there is NO ambiguity because:

[MapToApiVersion("1.0")]
[MapToApiVersion("2.0")]

helps ASP.NET select the correct method.

When to Use This Approach

Use single-controller versioning when:

  • Changes between versions are small
  • API is simple
  • Logic is mostly shared
  • Easier maintenance is preferred

When NOT to Use

Avoid this approach when:

  • V1 and V2 are completely different
  • Controller becomes too large
  • Business logic changes heavily

Then use:

Controllers/v1
Controllers/v2

approach instead.

Best Practice Recommendation

Scenario

Recommended Approach

Small changes between versions

Single controller

Large breaking changes

Separate folders/controllers

Enterprise large APIs

Separate version folders

Existing legacy clients

Support unversioned V1 route

Different between  [HttpGet(Name = "GetWeatherForecastDetails")] and [HttpGet("GetWeatherForecastDetails")]

This is a very important distinction in ASP.NET Core routing. These two may look similar, but they behave completely differently.


1. [HttpGet("GetWeatherForecastDetails")]

What it does

  • Defines the URL path (route template)
[HttpGet("GetWeatherForecastDetails")]

Resulting endpoint

GET /api/weatherforecast/GetWeatherForecastDetails

Meaning

You are explicitly telling ASP.NET:
“Call this method when this specific URL is hit.”


2. [HttpGet(Name = "GetWeatherForecastDetails")]

What it does

  • Assigns a name to the route
  • Does NOT change the URL
[HttpGet(Name = "GetWeatherForecastDetails")]

Resulting endpoint

GET /api/weatherforecast

Meaning

“This route has an internal name, which I can use later for URL generation.”


3. Side-by-side comparison

Feature

[HttpGet("...")]

[HttpGet(Name = "...")]

Affects URL?

Yes

No

Defines route path?

Yes

No

Used for routing incoming request

Yes

No

Used for URL generation

No

Yes

Required for API to work

Often yes

Optional


4. Real-world example

Using route template

[HttpGet("details")]
public IActionResult GetDetails()

👉 Call:

GET /api/weatherforecast/details

Using route name

[HttpGet(Name = "GetDetails")]
public IActionResult Get()

👉 Call:

GET /api/weatherforecast

👉 But inside code:

Url.RouteUrl("GetDetails");

5. When to use each

Use [HttpGet("...")] when:

  • You want different endpoints
  • You need multiple GET methods
  • You want meaningful URLs

Most common usage


Use Name = "..." when:

  • You need to generate URLs dynamically
  • Using:
    • CreatedAtRoute()
    • Url.RouteUrl()

Advanced / optional usage


6. Common mistake

[HttpGet(Name = "details")]
public IActionResult GetDetails()

This does NOT create:

/api/weatherforecast/details

It still remains:

/api/weatherforecast

7. Simple analogy

  • [HttpGet("details")]Actual address (door location)
  • Name = "details"Label in system (used internally)

Final takeaway

If you want to change the URL → use "..."
If you want to give a
name → use Name = "..."

 

Shall we use both [HttpGet(Name = "GetWeatherForecastDetails")] and [HttpGet("GetWeatherForecastDetails")]

Short answer: Yes, you can use both — and they serve different purposes.


How it works

You can combine them like this:

[HttpGet("GetWeatherForecastDetails", Name = "GetWeatherForecastDetails")]
public IEnumerable<WeatherForecast> GetDetails()
{
    ...
}

What each part does

Part

Purpose

"GetWeatherForecastDetails"

Defines the URL path

Name = "GetWeatherForecastDetails"

Assigns an internal route name


Result

URL to call API

GET /api/weatherforecast/GetWeatherForecastDetails

Internal usage (inside code)

Url.RouteUrl("GetWeatherForecastDetails");

When should you use both?

Use both when:

  • You want a custom URL path
  • AND you want to reference that route internally

Example scenario:

return CreatedAtRoute("GetWeatherForecastDetails", new { id = 1 }, data);

Best practice

Usually:

Most common

[HttpGet("details")]

When needed (advanced scenarios)

[HttpGet("details", Name = "GetDetailsRoute")]

Important note

  • The name does NOT affect routing
  • The string parameter DOES affect routing

Common mistake to avoid

[HttpGet(Name = "details")]

This does NOT create /details route


Clean recommendation

Use both only if you really need route naming (like in CreatedAtRoute).

Otherwise, keep it simple:

[HttpGet("details")]

Final takeaway

You can use both together
But:

  • "..." → controls URL
  • Name = "..." → used internally

 

 

 

What is use of 'Asp.Versioning.Mvc.ApiExplorer' LIBRARY ?

Asp.Versioning.Mvc.ApiExplorer — Purpose

Asp.Versioning.Mvc.ApiExplorer is mainly used for:

  • Swagger/OpenAPI integration
  • Discovering API versions
  • Generating separate Swagger documents for each API version

Without this package:

  • API versioning may still work
  • But Swagger usually cannot properly display:
    • V1
    • V2
    • Separate endpoints per version

Main Purpose

It helps Swagger understand:

/api/v1/weatherforecast
/api/v2/weatherforecast

are different API versions.

Required Packages

Usually both are installed together:

dotnet add package Asp.Versioning.Mvc
dotnet add package Asp.Versioning.Mvc.ApiExplorer

What happens WITHOUT ApiExplorer

You may see issues like:

  • Swagger shows duplicate endpoints
  • V1/V2 not separated
  • Swagger conflicts
  • Missing API versions
  • 404 swagger.json errors sometimes

Example problem:

Conflicting method/path combination

because Swagger sees:

GET /api/weatherforecast
GET /api/weatherforecast

and cannot differentiate versions.

What ApiExplorer Adds

It adds version metadata for:

  • Swagger
  • Endpoint discovery
  • API documentation

using Asp.Versioning;

using Asp.Versioning.ApiExplorer;

 

var builder = WebApplication.CreateBuilder(args);

 

builder.Services.AddControllers();

 

builder.Services.AddApiVersioning(options =>

{

    options.DefaultApiVersion = new ApiVersion(1, 0);

 

    options.AssumeDefaultVersionWhenUnspecified = true;

 

    options.ReportApiVersions = true;

})

 

.AddApiExplorer(options =>

{

    // Format: v1, v2

    options.GroupNameFormat = "'v'VVV";

 

    // Replaces version in URL

    options.SubstituteApiVersionInUrl = true;

});

 

 
builder.Services.AddSwaggerGen(options =>
{
    var provider = builder.Services.BuildServiceProvider()
        .GetRequiredService<Asp.Versioning.ApiExplorer.IApiVersionDescriptionProvider>();
 
    foreach (var description in provider.ApiVersionDescriptions)
    {
        options.SwaggerDoc(description.GroupName, new Microsoft.OpenApi.Models.OpenApiInfo
        {
            Title = $"API {description.ApiVersion}",
            Version = description.GroupName
        });
    }
});

AddApiExplorer() — Purpose

.AddApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";

    options.SubstituteApiVersionInUrl = true;
});

This is mainly used for:

  • Swagger
  • API documentation
  • API version discovery

It helps Swagger correctly understand and display versioned APIs.

1. options.GroupNameFormat = "'v'VVV"

Purpose

Defines how version names appear in Swagger.

Meaning of 'v'VVV

'v'

= literal character v

VVV

= API version number

Output

API Version

Group Name

1.0

v1

2.0

v2

1.1

v1.1

 

Query String, header and Media Type API Versioning.

Program.cs

using Asp.Versioning;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddApiVersioning(options =>
{
    // Default API Version
    options.DefaultApiVersion = new ApiVersion(1, 0);

    // Use default version when version not specified
    options.AssumeDefaultVersionWhenUnspecified = true;

    // Shows supported/deprecated versions in response headers
    options.ReportApiVersions = true;

    // Multiple Version Readers
    options.ApiVersionReader = ApiVersionReader.Combine(

        // Query String Versioning
        new QueryStringApiVersionReader(
"api-version"),

        // Header Versioning
        new HeaderApiVersionReader(
"x-api-version"),

        // Media Type Versioning
        new MediaTypeApiVersionReader(
"ct-api-version")
    );
});

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();

    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Controller

using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;

namespace WebAPIVersioning.Controllers
{
    [ApiController]

    [ApiVersion(
"1.0")]
    [ApiVersion(
"2.0")]

    [Route(
"api/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        // ---------------- Version 1 ----------------

        [HttpGet]

        [MapToApiVersion(
"1.0")]
        public IActionResult GetV1()
        {
            return Ok(new
            {
                Version =
"V1",
                Message =
"Weather Forecast Version 1"
            });
        }

        // ---------------- Version 2 ----------------

        [HttpGet]

        [MapToApiVersion(
"2.0")]
        public IActionResult GetV2()
        {
            return Ok(new
            {
                Version =
"V2",
                Message =
"Weather Forecast Version 2"
            });
        }
    }
}

How to Call APIs

1. Query String Versioning

GET https://localhost:7246/api/weatherforecast?api-version=1.0
GET https://localhost:7246/api/weatherforecast?api-version=2.0

2. Header Versioning

Headers

x-api-version: 1.0

Request

GET https://localhost:7246/api/weatherforecast

3. Media Type Versioning

Headers

Accept: application/json; ct-api-version=2.0

Request

GET https://localhost:7246/api/weatherforecast

What ApiVersionReader.Combine() Does

ApiVersionReader.Combine(...)

allows your API to read version information from multiple locations.

Version Detection Order

The API checks:

1.     Query String

2.     Header

3.     Media Type

until it finds a version.

Example

If request contains:

GET /api/weatherforecast?api-version=2.0

API uses:

Version 2.0

If query string absent, then it checks headers.

Best Practice

Versioning Type

Recommended Usage

URL Versioning

Public APIs

Header Versioning

Enterprise/internal APIs

Query String

Testing/simple APIs

Media Type

REST mature APIs

Important Note

If multiple versions are provided in the same request:

  • The first matching reader usually wins.

Example:

?api-version=1.0
x-api-version: 2.0

Query string may take priority depending on reader order.

 

 

 

 

 

Beginner Level Interview Questions

1. What is API versioning in .NET?

API versioning means managing different versions of an API in a .NET application.
It helps support old and new clients at the same time.

2. Why do we need API versioning?

We need API versioning to avoid breaking existing applications when APIs change.
It helps maintain backward compatibility.

3. What are the different types of API versioning available in ASP.NET Core?

Types of API versioning are URL versioning, Query String versioning, Header versioning, and Media Type versioning.
Each method sends the API version differently.

4. What is URL versioning?

URL versioning means passing the version in the API URL.
Example:

api/v1/products

5. How do you implement API versioning in ASP.NET Core?

Install the API versioning package and configure it in Program.cs.
Example:

builder.Services.AddApiVersioning();

6. Which NuGet package is commonly used for API versioning in .NET?

Common NuGet package:

Asp.Versioning.Mvc

7. What is the purpose of [ApiVersion] attribute?

[ApiVersion] defines the API version supported by a controller or action.
Example:

[ApiVersion("1.0")]

8. What does AssumeDefaultVersionWhenUnspecified mean?

It uses the default API version when the client does not provide any version.
This prevents version missing errors.

9. What is the default API version?

Default API version is the version automatically used when no version is specified.
Example:

DefaultApiVersion = new ApiVersion(1,0)

10. What is the purpose of ReportApiVersions?

ReportApiVersions adds supported and deprecated API versions in response headers.
It helps clients know available API versions.

Intermediate Level Interview Questions

1. What is the difference between URL versioning and query string versioning?
URL versioning keeps the version in the route like /api/v1/products.
Query string versioning keeps the version in the URL query like /api/products?api-version=1.0.
URL versioning is more clear and commonly used.

2. How does [MapToApiVersion] work?
[MapToApiVersion] is used to map an action method to a specific API version.
It helps when multiple methods exist inside the same controller for different versions.

[MapToApiVersion("2.0")]
public IActionResult GetV2()
{
    return Ok();
}

3. How do you support both versioned and non-versioned routes in the same API?
You can define multiple route attributes in the controller.
One route can include versioning and another can be normal.

[Route("api/v{version:apiVersion}/products")]
[Route("api/products")]

4. What is the purpose of v{version:apiVersion} in routing?
It is used to read the API version from the URL path.
version is the route parameter and apiVersion validates it as an API version.

api/v1/products

5. How do you create separate controllers for different API versions?
Create different controller classes for each version.
Use [ApiVersion] attribute and place them in separate folders or namespaces.

[ApiVersion("1.0")]
public class ProductsController : ControllerBase
{
}

6. What is the difference between Asp.Versioning.Mvc and Microsoft.AspNetCore.Mvc.Versioning?
Microsoft.AspNetCore.Mvc.Versioning is the old package name.
Asp.Versioning.Mvc is the newer package with updated support and features.
New projects should use Asp.Versioning.Mvc.

7. How do you configure Swagger for API versioning?
Create Swagger documents for each API version.
Use IApiVersionDescriptionProvider to generate separate Swagger endpoints.

options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
options.SwaggerEndpoint("/swagger/v2/swagger.json", "v2");

8. What is the purpose of AddApiExplorer() in API versioning?
AddApiExplorer() helps Swagger discover API version details.
It groups endpoints based on versions and generates separate documentation.

builder.Services.AddApiVersioning()
                .AddApiExplorer();

9. What does SubstituteApiVersionInUrl = true do?
It replaces the {version} placeholder in routes with the actual API version.
Without this, Swagger may show {version} instead of v1 or v2.

options.SubstituteApiVersionInUrl = true;

10. How do you deprecate an API version in ASP.NET Core?
Use the Deprecated = true property inside [ApiVersion].
It marks the version as old and Swagger shows it as deprecated.

[ApiVersion("1.0", Deprecated = true)]

Advanced Level Interview Questions

1. How do you implement header-based API versioning in ASP.NET Core?
Header versioning reads the API version from request headers.
You can configure it using HeaderApiVersionReader.

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader =
        new HeaderApiVersionReader("api-version");
});

2. How do you implement media type API versioning?
Media type versioning reads the version from the Accept header.
It is useful when clients use content negotiation.

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader =
        new MediaTypeApiVersionReader("version");
});

3. How does API versioning work internally with route constraints?
Route constraints check whether the requested version matches the controller version.
apiVersion constraint helps ASP.NET Core select the correct endpoint.
If no match is found, it returns an error response.

4. How do you handle breaking changes between API versions?
Create a new API version instead of modifying the old one.
Keep old endpoints working until clients migrate to the new version.
This avoids breaking existing applications.

5. How do you maintain backward compatibility in large enterprise APIs?
Keep older API versions active for some time.
Avoid removing fields or changing response formats suddenly.
Use proper documentation and deprecation notices.

6. What are the advantages and disadvantages of single-controller versioning vs separate-controller versioning?
Single-controller versioning reduces duplicate code but becomes hard to manage for many versions.
Separate-controller versioning is cleaner and easier to maintain but may increase repeated code.
Large projects usually prefer separate controllers.

7. How do you customize API version selection behavior in ASP.NET Core?
You can create a custom API version selector.
It decides which version should be selected when the client does not provide one.

options.ApiVersionSelector =
    new CurrentImplementationApiVersionSelector(options);

8. How would you migrate an existing unversioned API to a versioned API without breaking existing clients?
Keep the old routes working while adding new versioned routes.
Set a default API version for old clients.
Gradually move clients to versioned endpoints.

9. How do you version Minimal APIs in .NET?
Minimal APIs use ApiVersionSet and MapToApiVersion.
You can assign versions directly while mapping endpoints.

app.MapGet("/products", () => "v1")
   .MapToApiVersion(1.0);

10. What challenges can occur when integrating Swagger with multiple API versions and how do you resolve them?
Common issues are duplicate endpoints and wrong Swagger JSON paths.
Use AddApiExplorer() and create separate Swagger documents for each version.
Enable SubstituteApiVersionInUrl = true to fix version placeholders.

 

1. How do you design API versioning strategy for microservices?
Each microservice should manage its own API versions independently.
Use clear version naming like v1, v2 and avoid frequent breaking changes.
API Gateway can help route requests to correct versions.

2. How do you handle API versioning in API Gateway?
The API Gateway routes client requests to the correct backend version.
It can expose URLs like /v1/orders and /v2/orders.
This keeps version management centralized.

3. How do you manage versioning in distributed systems?
Services should support backward compatibility during deployments.
Use contract-based communication and avoid sudden response changes.
Version APIs carefully to prevent service failures.

4. How do you test multiple API versions effectively?
Create separate test cases for each API version.
Use automated integration and regression testing.
Swagger and Postman collections also help in testing.

5. How do you monitor usage of deprecated API versions?
Use logging and API monitoring tools to track requests.
Check which clients still use old versions.
Notify users before removing deprecated APIs.

6. How do you secure different API versions with authentication and authorization?
Apply authentication and authorization policies per version if needed.
Older versions may use different security methods.
JWT and OAuth are commonly used for securing APIs.

7. How do you handle database schema changes across API versions?
Avoid breaking database changes immediately.
Use migrations and support both old and new fields during transition.
Mapping layers help manage schema differences.

8. How do you implement API versioning with OData in ASP.NET Core?
OData supports versioning using route configuration.
Each version can expose different OData models and endpoints.
Versioned routes are configured separately.

routeBuilder.MapVersionedODataRoute(
    "v1",
    "api/v{version:apiVersion}",
    model);

9. How do you manage API documentation for multiple versions in large systems?
Create separate Swagger documents for every version.
Clearly mark deprecated APIs in documentation.
Keep release notes updated for clients.

10. How do you version APIs in cloud-native applications using Kubernetes and Azure API Management?
Use API Management to expose multiple API versions.
Kubernetes deployments can run different API versions together.
Traffic routing helps during gradual upgrades.

11. How do you apply semantic versioning in APIs?
Semantic versioning uses Major.Minor.Patch format.
Major version is for breaking changes, minor for new features, and patch for fixes.
Example: v2.1.0.

12. How do you reduce duplicate business logic across API versions?
Keep shared business logic inside services or repositories.
Controllers should only handle version-specific changes.
This reduces repeated code.

13. How do you implement sunset policies for old API versions?
Mark APIs as deprecated before removal.
Send warning headers or documentation notices to clients.
Give enough migration time before disabling old versions.

14. How do you handle SDK/client compatibility when API versions change?
Maintain backward compatibility whenever possible.
Release updated SDK versions for new APIs.
Document all breaking changes clearly.

15. How do caching and CDN behave with different API versions?
Each API version should have separate cache entries.
Version information must be part of the cache key or URL.
This avoids incorrect cached responses.

16. How do you implement version-neutral controllers in ASP.NET Core?
Use [ApiVersionNeutral] for controllers that work for all versions.
These controllers are accessible without version restrictions.

[ApiVersionNeutral]
public class HealthController : ControllerBase
{
}

17. How do you support rolling upgrades between API versions?
Run old and new API versions together for some time.
Gradually move traffic to the new version.
This reduces downtime and deployment risk.

18. How do you maintain API contracts in CI/CD pipelines?
Use automated contract and integration tests in the pipeline.
Validate request and response formats before deployment.
Swagger schema validation is also useful.

19. How do you implement API versioning in GraphQL or gRPC services?
GraphQL usually avoids versioning by evolving schemas carefully.
gRPC versioning is commonly done using package names or namespaces.
Breaking changes should be minimized.

20. What are the best practices for enterprise API versioning?
Use consistent versioning strategy across all services.
Avoid unnecessary breaking changes and document everything clearly.
Monitor deprecated APIs and maintain backward compatibility.

 

 

Asp.Versioning.Mvc
Used to add API versioning support in ASP.NET Core APIs.

Asp.Versioning.Mvc.ApiExplorer
Helps Swagger separate and display APIs by version.

Swashbuckle.AspNetCore
Used to generate Swagger UI and API documentation.


/api/v1/users
API version is passed in the URL path.

/api/v2/users
Calls version 2 of the same API endpoint.


/api/users?api-version=1.0
API version is passed in the query string.


api-version: 1.0
API version is sent through request headers.


Accept: application/json;v=1.0
API version is sent in the Accept header using media type versioning.


builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);

    // If version not specified -> use V1
    options.AssumeDefaultVersionWhenUnspecified = true;

    options.ReportApiVersions = true;
});

DefaultApiVersion = new ApiVersion(1, 0)
Sets API version 1.0 as the default version.

AssumeDefaultVersionWhenUnspecified = true
Uses the default version if the client does not send a version.

ReportApiVersions = true
Adds supported and deprecated API versions in response headers.


[ApiVersion("1.0")]

Defines that the controller or action belongs to API version 1.0.


[Route("api/[controller]")]

Creates a route without version in the URL.


[Route("api/v{version:apiVersion}/[controller]")]

Creates a route with API version in the URL.


[ApiVersion("1.0", Deprecated = true)]

Marks API version 1.0 as deprecated or old.


[MapToApiVersion("1.0")]

Maps a specific action method to API version 1.0.


[HttpGet(Name = "GetWeatherForecastDetails")]

Gives a name to the endpoint for URL generation.


[HttpGet("GetWeatherForecastDetails")]

Defines the URL path for the endpoint.


Asp.Versioning.Mvc.ApiExplorer
Used by Swagger to discover and group APIs by version.


.AddApiExplorer(options =>
{
    // Format: v1, v2
    options.GroupNameFormat = "'v'VVV";

    // Replaces version in URL
    options.SubstituteApiVersionInUrl = true;
});

GroupNameFormat = "'v'VVV"
Formats Swagger version names like v1 and v2.

SubstituteApiVersionInUrl = true
Automatically replaces the version placeholder in routes.


builder.Services.AddSwaggerGen(options =>
{
    var provider = builder.Services.BuildServiceProvider()
        .GetRequiredService<Asp.Versioning.ApiExplorer.IApiVersionDescriptionProvider>();

    foreach (var description in provider.ApiVersionDescriptions)
    {
        options.SwaggerDoc(description.GroupName, new Microsoft.OpenApi.Models.OpenApiInfo
        {
            Title = $"API {description.ApiVersion}",
            Version = description.GroupName
        });
    }
});

Creates separate Swagger documents for each API version.


options.ReportApiVersions = true;

Shows supported and deprecated versions in response headers.


options.ApiVersionReader = ApiVersionReader.Combine(

Allows the API to read version information from multiple places.


new QueryStringApiVersionReader("api-version")

Reads API version from the query string.


new HeaderApiVersionReader("x-api-version")

Reads API version from request headers.


new MediaTypeApiVersionReader("ct-api-version")

Reads API version from the media type or Accept header.