ASP.NET Core 8 Web API -

Versioning

Versioning is essential in API development to ensure backward compatibility and allow for incremental improvements without breaking existing clients. ASP.NET Core 8 provides robust support for API versioning through various methods. This guide covers how to implement API versioning, including URL segment versioning, query string versioning, header versioning, and best practices.


1. Introduction to API Versioning

API versioning allows you to maintain multiple versions of your API simultaneously. This is critical when making breaking changes to your API while still supporting clients using older versions.

Why Use API Versioning?


2. Installing API Versioning

ASP.NET Core provides a package specifically for API versioning. Install it using the .NET CLI.

        
            
dotnet add package Microsoft.AspNetCore.Mvc.Versioning
dotnet add package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer

        
    

3. Configuring API Versioning

Configure API versioning in the Program.cs file.

        
            
var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();

// Add API versioning
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
    options.ApiVersionReader = new UrlSegmentApiVersionReader();
});

// Add versioned API explorer
builder.Services.AddVersionedApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

var app = builder.Build();

app.UseHttpsRedirection();

app.MapControllers();
app.Run();

        
    

Configuration Parameters:


4. Versioning by URL Segment

URL segment versioning includes the version in the URL path. This is the most commonly used versioning strategy.

4.1 Configure URL Segment Versioning

Ensure the ApiVersionReader is set to UrlSegmentApiVersionReader.

        
            
options.ApiVersionReader = new UrlSegmentApiVersionReader();

        
    

4.2 Define Versioned Controllers

Define controllers with versioned routes.

        
            
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2" });
}

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2", "Product3" });
}

        
    

Explanation:


5. Versioning by Query String

Query string versioning includes the version in the query string of the URL.

5.1 Configure Query String Versioning

Set the ApiVersionReader to QueryStringApiVersionReader.

        
            
options.ApiVersionReader = new QueryStringApiVersionReader("v");

        
    

5.2 Define Versioned Controllers

Define controllers without versioned routes. The version is determined by the query string.

        
            
[ApiVersion("1.0")]
[Route("api/products")]
[ApiController]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2" });
}

[ApiVersion("2.0")]
[Route("api/products")]
[ApiController]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2", "Product3" });
}

        
    

Explanation:


6. Versioning by HTTP Header

Header versioning includes the version in a custom HTTP header.

6.1 Configure Header Versioning

Set the ApiVersionReader to HeaderApiVersionReader.

        
            
options.ApiVersionReader = new HeaderApiVersionReader("x-api-version");

        
    

6.2 Define Versioned Controllers

Define controllers without versioned routes. The version is determined by the custom header.

        
            
[ApiVersion("1.0")]
[Route("api/products")]
[ApiController]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2" });
}

[ApiVersion("2.0")]
[Route("api/products")]
[ApiController]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2", "Product3" });
}

        
    

Explanation:


7. Combining Versioning Methods

You can combine different versioning methods to provide flexibility to clients.

7.1 Configure Multiple Versioning Methods

Set the ApiVersionReader to combine multiple readers.

        
            
options.ApiVersionReader = ApiVersionReader.Combine(
    new UrlSegmentApiVersionReader(),
    new QueryStringApiVersionReader("v"),
    new HeaderApiVersionReader("x-api-version"));

        
    

7.2 Define Versioned Controllers

Define controllers as before, ensuring they can respond to any of the specified versioning methods.

        
            
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2" });
}

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2", "Product3" });
}

        
    

Explanation:


8. API Versioning Best Practices


9. Comprehensive Example

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

// Add services to the container
builder.Services.AddControllers();

// Add API versioning
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
    options.ApiVersionReader = ApiVersionReader.Combine(
        new UrlSegmentApiVersionReader(),
        new QueryStringApiVersionReader("v"),
        new HeaderApiVersionReader("x-api-version"));
});

// Add versioned API explorer
builder.Services.AddVersionedApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

var app = builder.Build();

app.UseHttpsRedirection();

app.MapControllers();
app.Run();

        
    


Versioned Controllers:
        
            
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2" });
}

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok(new[] { "Product1", "Product2", "Product3" });
}

        
    

Conclusion

API versioning is crucial for maintaining backward compatibility and allowing for incremental improvements. By implementing URL segment, query string, and header versioning, you can provide flexibility to your API clients. Following best practices ensures that your API remains reliable and easy to use. This comprehensive guide provides the tools and knowledge to effectively implement API versioning in your ASP.NET Core 8 Web API projects.