Skip to content

API Versioning in ASP.NET Core 8 Web API

Problem Statement

When migrating ASP.NET Core Web API projects from .NET 6/7 to .NET 8, the API versioning implementation breaks due to deprecated packages. Developers using the Microsoft.AspNetCore.Mvc.ApiExplorer package encounter compatibility issues, as this package is now deprecated in .NET 8. Attempting to replace it with Asp.Versioning.Mvc.ApiExplorer causes errors since the AddVersionedApiExplorer extension method is unavailable. This results in a runtime exception:

Unable to resolve service for type 'Asp.Versioning.ApiExplorer.IApiVersionDescriptionProvider'...

The solution requires updated package references and a revised service configuration approach compatible with .NET 8.

Solution

1. Install Required NuGet Packages

Install both versioning packages via NuGet Package Manager or CLI:

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

2. Configure API Versioning Services

Update the service configuration in Program.cs by chaining AddApiExplorer() to AddApiVersioning():

csharp
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
})
.AddApiExplorer(options => // Chain to AddApiVersioning
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

3. Update Swagger Configuration

Modify your Swagger setup to use the new package's IApiVersionDescriptionProvider:

csharp
builder.Services.AddSwaggerGen();

// Register configuration for Swagger versions
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();

Ensure your ConfigureSwaggerOptions class remains unchanged from your .NET 7 implementation:

csharp
using Asp.Versioning.ApiExplorer;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

public class ConfigureSwaggerOptions : IConfigureNamedOptions<SwaggerGenOptions>
{
    private readonly IApiVersionDescriptionProvider _provider;

    public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider)
    {
        _provider = provider;
    }

    public void Configure(SwaggerGenOptions options)
    {
        foreach (var description in _provider.ApiVersionDescriptions)
        {
            options.SwaggerDoc(
                description.GroupName,
                CreateVersionInfo(description));
        }
    }

    private static OpenApiInfo CreateVersionInfo(ApiVersionDescription description)
    {
        var info = new OpenApiInfo()
        {
            Title = "Your API",
            Version = description.ApiVersion.ToString(),
            Description = "API Description"
        };
        
        if (description.IsDeprecated)
            info.Description += " - DEPRECATED";
            
        return info;
    }
    
    public void Configure(string name, SwaggerGenOptions options) => Configure(options);
}

Complete Program.cs Example

csharp
using Asp.Versioning.ApiExplorer;

var builder = WebApplication.CreateBuilder(args);

// Add versioning and Swagger
builder.Services.AddApiVersioning(options =>
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true;
})
.AddApiExplorer(options =>
{
    options.GroupNameFormat = "'v'VVV";
    options.SubstituteApiVersionInUrl = true;
});

builder.Services.AddSwaggerGen();
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI(options =>
{
    var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
    
    foreach (var description in provider.ApiVersionDescriptions)
    {
        options.SwaggerEndpoint(
            $"/swagger/{description.GroupName}/swagger.json",
            description.GroupName.ToUpperInvariant());
    }
});

app.Run();

Explanation

Why .NET 8 Changes Matter

The Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer package was deprecated in .NET 8. The new Asp.Versioning.Mvc.ApiExplorer package:

  • Uses a modified service registration pattern
  • Requires chaining AddApiExplorer() to AddApiVersioning()
  • Returns IApiVersioningBuilder for fluent configuration

Key Differences from Older Versions

.NET 6/7.NET 8
AddVersionedApiExplorerUse AddApiExplorer() extension
Separate service callsChained configuration
Deprecated packagesAsp.Versioning namespace

Resolving the Service Error

The original IApiVersionDescriptionProvider error occurs because:

  1. The new package uses the Asp.Versioning.ApiExplorer namespace
  2. Service registration requires chained configuration
  3. The dependency injection container never receives the service without AddApiExplorer()

The AddApiExplorer extension registers the required IApiVersionDescriptionProvider service in the DI container, enabling injection into ConfigureSwaggerOptions.

Swagger UI Considerations

When configuring Swagger UI (Step 3 in Program.cs), note:

  • You must resolve IApiVersionDescriptionProvider from the service container
  • Group names follow the pattern defined in GroupNameFormat ('v'VVV → v1.0, v2.1, etc.)
  • Deprecation status appears automatically when using description.IsDeprecated

Maintenance Tip

Consistent versioning is crucial for API stability. Test all endpoints with tools like Swagger UI or Postman after version changes.

Deprecation Handling

Use [ApiVersion("1.0", Deprecated = true)] to mark deprecated API versions. This automatically triggers the "deprecated" flag in Swagger documentation.