ASP.NET Core – Web API Versioning

前言

项目持续维护, API 就需要版本控制. ASP.NET Core 有官方的插件专门处理 API 版本控制.

 

主要参考

Your Guide to REST API Versioning in ASP.NET Core

Asp.Net.Core WebApi 4种版本控制的方式

How to use API versioning in ASP.NET Core

ASP.NET Core WebApi版本控制的实现 (有讲到 swagger 哦)

Asp.Net Core 5 - API Versioning

Github aspnet-api-versioning

Docs – aspnet-api-versioning(最新版本,上面的是旧版本的参考)

 

 

安装 nuget

dotnet add package Asp.Versioning.Mvc

 

Program.cs

复制代码
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddApiVersioning(options =>
{
    options.AssumeDefaultVersionWhenUnspecified = true; // 如果请求没有声明就使用默认版本
    options.DefaultApiVersion = new ApiVersion(1, 0); // 默认版本
    options.ReportApiVersions = true; // 在 header 返回支持的版本 (尤其用于 deprecated 弃用的 API)
}).AddMvc();
//builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    //app.UseSwagger();
    //app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
复制代码

主要是 .AddApiVersioning 的配置.

注释掉 Swagger 是因为 versioning 会导致 Swagger 需要额外配置. 看这篇: Swagger API Versioning.

 

两种管理方式

第一种方式: 一个 controller 多个 version 

复制代码
namespace WebApiVersioning.Controllers
{
    [ApiController]
    // 表示这个 Controller 支持 1.0 和 2.0
    [ApiVersion("1.0", Deprecated = true)] // Deprecated 表示废弃了, 会在返回的 header 表示, 虽然是废弃了, 但是依然会跑和 response 的哦 (自行处理)
    [ApiVersion("2.0")]
    [Route("api/v{version:apiVersion}/[controller]")] // 声明 version in path
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet(Name = "GetWeatherForecast"), MapToApiVersion("1.0")] // 通过 MapToApiVersion 声明这个 action 是 for 哪个 version 
        public IEnumerable<WeatherForecast> Get_v1() // 名字是 v1
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)] + " v1"
            })
            .ToArray();
        }

        [HttpGet(Name = "GetWeatherForecast"), MapToApiVersion("2.0")]
        public IEnumerable<WeatherForecast> Get_v2() // 名字是 v2
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55), 
                Summary = Summaries[Random.Shared.Next(Summaries.Length)] + " v2"
            })
            .ToArray();
        }

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
    }
}
复制代码

请求 v1.0 就会执行 Get_v1, v2.0 就是 Get_v2

header response 会表示 api-supported-versions 和 api-deprecated-versions (如果有).

如果都没有 deprecated, 会是这样

 

第二种方式: 1 个 controller 一个 version

可以通过 namespace 或者 controller name 来设定版本号, 关键就是不要把 Action 放一起.

复制代码
namespace WebApiVersioning.Controllers.v1
{
    [ApiController]
    [ApiVersion("1.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet(Name = "GetWeatherForecast")] 
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)] + " v1"
            })
            .ToArray();
        }
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
    }
}
namespace WebApiVersioning.Controllers.v2
{
    [ApiController]
    [ApiVersion("2.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)] + " v2"
            })
            .ToArray();
        }
      
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
    }
}
复制代码

两种方法各有所长. 并用是可以的.

 

Non-version

不需要 API versioning 的就加上 attribute

[ApiVersionNeutral]

 

Range Version

当我们发布新的 version 时,绝大部分的 API 是向后兼容的,所以在 define API version 时,我们会希望这样写 "^1.0" 表示 1.0 - 1.9 都可以用。

[HttpGet, MapToApiVersion("^1.0")]
public IEnumerable<Product> Get_v1()
{
  return [
    new () { Id = 1, Name = "p1" },
    new () { Id = 2, Name = "p1" }
  ];
}

但它不支持,你唯一能做的是写多几个 MapToApiVersion("1.1"), MapToApiVersion("1.2")

相关 feature request 很少就有提了 Github – API range attribute,并且他们也做了一个扩展来支持 PB.ITOps.AspNetCore.Versioning

不清楚还有没有人在维护。

 

posted @   兴杰  阅读(746)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
历史上的今天:
2018-10-25 Angular 学习笔记 (Material Datepicker)
点击右上角即可分享
微信分享提示