Step-by-Step Guide to Web API Versioning with Multiple Versions, Swagger Support, and Exception Handling in .NET Core using C#

Nuno Cancelo
4 min readAug 8, 2023

Web API versioning is crucial when developing and maintaining APIs to ensure seamless updates and backward compatibility with client applications. This article will explore how to implement Web API versioning in a .NET Core application using C#. Additionally, we will leverage the power of Swagger to provide documentation for each API version. Moreover, we will enhance our API by adding exception-handling capabilities.

Prerequisites

Before we begin, make sure you have the following installed on your machine:

  1. .NET Core SDK (6 or later)
  2. Visual Studio or Visual Studio Code (optional but recommended)

Step 1: Setting Up the Project

Let’s start by creating a new .NET Core Web API project. Open your terminal or command prompt and run the following command:

dotnet new webapi -n ApiVersioningWithSwagger
cd ApiVersioningWithSwagger

This command will create a new .NET Core Web API project named “ApiVersioningWithSwagger.”

Step 2: Install Required NuGet Packages

To enable versioning, Swagger support, and exception handling, we need to install the following NuGet packages:

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

Step 3: Configure Web API Versioning

Open the Program.cs file, which is located in the root of your project, add the following code to configure API versioning:

using Microsoft.AspNetCore.Mvc;

//...

// Configure Web API Versioning
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});

Step 4: Create API Controllers with Multiple Versions

Let’s create two versions of a sample API controller to demonstrate versioning. Create a new folder named “Controllers” at the root of your project. Inside this folder, add two files:

using Microsoft.AspNetCore.Mvc;

namespace ApiVersioningWithSwagger.Controllers.v1;

[ApiController]
[Route("api/v{version:apiVersion}/weatherforecast")]
[ApiVersion("1.0")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild"
};

private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}

v1 folder > WeatherForecastController.cs

using Microsoft.AspNetCore.Mvc;

namespace ApiVersioningWithSwagger.Controllers.v2;

[ApiController]
[Route("api/v{version:apiVersion}/weatherforecast")]
[ApiVersion("2.0")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}

[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}

v2 folder > WeatherForecastController.cs

These two controllers represent versions 1.0 and 2.0 of the WeatherForecastController, each returning a different message in the response.

Step 5: Configure Swagger for API Documentation

Open the Program.cs file, which is located in the root of your project, add the following code to enable Swagger documentation:

using Microsoft.AspNetCore.Mvc.Versioning;

// ...

// Configure Swagger for API Documentation
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API V1", Version = "v1" });
c.SwaggerDoc("v2", new OpenApiInfo { Title = "API V2", Version = "v2" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});

In this code snippet, we are configuring two Swagger documents, one for each API version.

Step 6: Include Versioned API Controllers in Swagger

Include versioned controllers in Swagger:

using Microsoft.AspNetCore.Mvc.Versioning;

// ...
// Include Versioned API Controllers in Swagger
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1");
c.SwaggerEndpoint("/swagger/v2/swagger.json", "API V2");
});

Step 7: Add Exception Handling

Now, let’s enhance our API by adding exception-handling capabilities. Open the Program.cs file, which is located in the root of your project, add the following code to add an exception handler:

// ...

app.UseExceptionHandler("/error");

In this code snippet, we add an exception handler using the UseExceptionHandler middleware. When an exception occurs in your API, it will be directed to the /error endpoint.

Step 8: Create the Error Controller

Create a new folder named “Controllers” in the root of your project if it doesn’t exist. Inside this folder, add a new file named ErrorController.cs:

using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;

namespace ApiVersioningWithSwagger.Controllers
{
[ApiExplorerSettings(IgnoreApi = true)]
public class ErrorController : ControllerBase
{
[Route("/error")]
public async Task<IActionResult> Error()
{
Exception? exception = HttpContext.Features.Get<IExceptionHandlerFeature>().Error;
await Task.CompletedTask;
return Problem(detail: exception.Message);
}
}
}

This controller handles exceptions and returns a problem details response with the exception message.

Step 9: Test the API

Build and run the application using the following command:

dotnet run

Open your browser and navigate to https://localhost:5001/swagger. This will open the Swagger UI, showing the documentation for both API versions. You can explore and test the available endpoints directly from the Swagger UI.

Step 10: Test API Versioning

You can use a tool like Postman or the browser to test the API versioning.

For version 1.0, open a browser or use a tool like Postman and navigate to:

https://localhost:5001/api/v1/weatherforecast

For version 2.0, use the following URL:

https://localhost:5001/api/v2/weatherforecast

You should receive the corresponding messages from each version of the API.

Conclusion

This article covers how to implement Web API versioning in a .NET Core application using C#. We’ve also integrated Swagger to provide documentation for each API version. Additionally, we enhanced our API by adding exception-handling capabilities, allowing us to handle errors and gracefully provide meaningful responses to clients.

Following these steps, you have learned how to create a well-structured and versioned API while ensuring a smooth development and maintenance process. Incorporating exception handling further improves the reliability and user experience of your API.

Remember that proper versioning and exception handling are essential to a robust and user-friendly API. By mastering these techniques, you can confidently build efficient and resilient APIs. Happy coding!

--

--

Nuno Cancelo
Nuno Cancelo

Written by Nuno Cancelo

Senior Software Engineer | Dev Lead | Tech Lead | Code Cleaner | Community Leader | Puzzle Solver | Dev Evangelist | Beer Lover

Responses (2)