API versioning strategies using Asp.Versioning. URL segment, header, query string approaches, sunset policies, and OpenAPI integration. Trigger: API version, versioning, Asp.Versioning, v1, v2.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
/api/v1/orders) is the most common and recommended// Program.cs
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = new UrlSegmentApiVersionReader();
})
.AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
[ApiController]
[Route("api/v{version:apiVersion}/orders")]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public sealed class OrdersController(ISender sender) : ControllerBase
{
[HttpGet]
[MapToApiVersion("1.0")]
public async Task<ActionResult<List<OrderV1Response>>> GetOrdersV1(
CancellationToken ct)
{
var result = await sender.Send(new ListOrdersV1Query(), ct);
return Ok(result);
}
[HttpGet]
[MapToApiVersion("2.0")]
public async Task<ActionResult<PagedList<OrderV2Response>>> GetOrdersV2(
[FromQuery] OrderFilter filter, CancellationToken ct)
{
var result = await sender.Send(new ListOrdersV2Query(filter), ct);
return Ok(result);
}
}
// Or separate controllers per version
[ApiController]
[Route("api/v{version:apiVersion}/orders")]
[ApiVersion("1.0", Deprecated = true)]
public sealed class OrdersV1Controller : ControllerBase { }
[ApiController]
[Route("api/v{version:apiVersion}/orders")]
[ApiVersion("2.0")]
public sealed class OrdersV2Controller : ControllerBase { }
var versionSet = app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(1, 0))
.HasApiVersion(new ApiVersion(2, 0))
.ReportApiVersions()
.Build();
var v1 = app.MapGroup("/api/v{version:apiVersion}")
.WithApiVersionSet(versionSet);
v1.MapGet("/orders", GetOrdersV1)
.MapToApiVersion(new ApiVersion(1, 0));
v1.MapGet("/orders", GetOrdersV2)
.MapToApiVersion(new ApiVersion(2, 0));
builder.Services.AddApiVersioning(options =>
{
options.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version");
});
// Client sends: X-Api-Version: 2.0
builder.Services.AddApiVersioning(options =>
{
options.ApiVersionReader = new QueryStringApiVersionReader("api-version");
});
// Client requests: /api/orders?api-version=2.0
builder.Services.AddApiVersioning(options =>
{
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("X-Api-Version"),
new QueryStringApiVersionReader("api-version"));
});
builder.Services.AddApiVersioning(options =>
{
options.Policies.Sunset(1.0)
.Effective(new DateTimeOffset(2025, 6, 1, 0, 0, 0, TimeSpan.Zero))
.Link("https://docs.{Company}.com/api/migration-guide")
.Title("v1 to v2 Migration Guide")
.Type("text/html");
});
// Response header: Sunset: Sat, 01 Jun 2025 00:00:00 GMT
// Response header: Link: <https://docs.{Company}.com/api/migration-guide>; ...
builder.Services.AddOpenApi("v1");
builder.Services.AddOpenApi("v2");
// Each document at /openapi/v1.json and /openapi/v2.json
app.MapOpenApi();
Asp.Versioning package reference in .csprojAddApiVersioning in Program.cs[ApiVersion] attributes on controllersv{version:apiVersion} in route templatesAsp.Versioning.Http (minimal API) or Asp.Versioning.Mvc.ApiExplorer (controllers)AddApiVersioning with default version and reader[ApiVersion] to existing controllers (start with "1.0")| Strategy | Pros | Cons | Use When |
|---|---|---|---|
| URL segment | Visible, cacheable, simple | Version in URL | Default choice |
| Header | Clean URLs | Hidden, harder to test | Internal APIs |
| Query string | Easy to add | Pollutes query params | Legacy compat |