本文属于OData系列

目录


对外提供WEBAPI时,如果遇上了版本升级,那么控制WEBAPI的版本也是非常必要的。OData官方提供了版本控制以及管理的解决方案,我个人是实践体会是不好用,好在社区提供了对应的nuget包,与.NET主版本同步更新。

介绍

ASP.NET API Versioning是一个提供ASP.NET WEBAPI版本管理的包,支持ASP.NET、ASP.NET CORE、ASP.NET CORE ODATA,作者以前是微软的员工,现在不在微软工作了,因此原先的命名空间不能继续用了。现在这个项目已经加入.NET Foundation,作者也非常活跃。

版本管理

首先对现有的项目安装这个包:

Install-Package Asp.Versioning.OData

在Program.cs文件中修改一下:

var builder = WebApplication.CreateBuilder( args );

builder.Services.AddControllers().AddOData();
builder.Services.AddProblemDetails();
builder.Services.AddApiVersioning().AddOData(
options =>
{
options.AddRouteComponents();
} ); var app = builder.Build(); app.MapControllers();
app.Run();

然后在需要控制版本的控制器上加上[ApiVersion]修饰就可以了。

[ApiVersion( 1.0 )]
public class PeopleController : ODataController
{
[EnableQuery]
public IActionResult Get() => Ok( new[] { new Person() } );
}

注意,默认的版本是1.0,不过最好显式声明一下。

EDM升级

EDM根据版本不同也会有一些区别,需要分别进行配置,原来的GetEdm()模式显得有点麻烦,而EDM配置在这个库中变得非常灵活,使用的是Configuration模式。

示例代码如下:

public class DeviceInfoModelConfiguration : IModelConfiguration
{
public void Apply(ODataModelBuilder builder, ApiVersion apiVersion, string routePrefix)
{
switch (apiVersion.MajorVersion)
{
case 1:
builder.EntitySet<DeviceInfo>("DeviceInfoes").EntityType.HasKey(p => p.DeviceId);
break;
case 2:
builder.EntitySet<DeviceInfo>("DeviceInfos").EntityType.HasKey(p => p.DeviceId).Ignore(w => w.Layout);
break;
default:
break;
};
}
}

只需要实现IModelConfiguration接口,并在Apply函数中根据版本对实体或者DTO对象进行配置,不同版本的EDM可以不一样。

一般实践是一个实体对象一个IModelConfiguration,方便后面管理。

配置Swagger

因为有重复配置的模型,直接使用默认的Swagger会报错,这个时候需要使用到Versioned API Explorer,对Swagger拓展版本信息。

Install-Package Asp.Versioning.OData.ApiExplorer

安装Asp.Versioning.OData.ApiExplorer,重新改造一下Program.cs文件:

var builder = WebApplication.CreateBuilder( args );

builder.Services.AddControllers().AddOData();
builder.Services.AddProblemDetails();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddApiVersioning()
.AddOData( options => options.AddRouteComponents() )
.AddODataApiExplorer(
// format the version as "'v'major[.minor][-status]"
options => options.GroupNameFormat = "'v'VVV" ); services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(); var app = builder.Build(); app.UseSwagger();
app.UseSwaggerUI(
options =>
{
foreach ( var description in app.DescribeApiVersions() )
{
var url = $"/swagger/{description.GroupName}/swagger.json";
var name = description.GroupName.ToUpperInvariant();
options.SwaggerEndpoint( url, name );
}
} );
app.MapControllers();
app.Run();

还需要一个配置的类如下:

public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
readonly IApiVersionDescriptionProvider provider; public ConfigureSwaggerOptions( IApiVersionDescriptionProvider provider ) =>
this.provider = provider; public void Configure( SwaggerGenOptions options )
{
foreach ( var description in provider.ApiVersionDescriptions )
{
options.SwaggerDoc(
description.GroupName,
new OpenApiInfo()
{
Title = $"Example API {description.ApiVersion}",
Version = description.ApiVersion.ToString(),
} );
}
}
}

这样,swagger界面就可以下拉选择不同版本的API了。

旧系统升级

WEBAPI Versioning对这个内容有介绍,其中需要注意的是,基于路径的版本匹配并不支持默认版本的特性,对于以前系统直接使用api/开头的控制器,并不能直接默认转到到api/v1(参考介绍)。为了兼容旧系统,我们只能在ASP.NET CORE的管线上想想办法:插入一个中间件,对路径进行判断,如果是api开头的,就直接转到api/v1;如果是api/v开头的,那么就直接下一步。

    public class RedirectMiddlewareForV1
{
private readonly RequestDelegate _next; public RedirectMiddlewareForV1(RequestDelegate next)
{
_next = next;
} public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path.StartsWithSegments("/api") && !context.Request.Path.Value.StartsWith("/api/v"))
{
context.Response.Redirect(context.Request.Path.Value.Replace("/api/", "/api/v1/"));
}
else
{
await _next(context);
}
} }

然后在configure函数中注册这个中间件就可以了。

app.UseMiddleware<RedirectMiddlewareForV1>();

请注意,context.Request.Path.StartsWithSegments函数只能匹配完整的路径词汇,/api/v2去匹配/api/v会返回false。

FAQ

  1. 无法正确显示不同版本的Swagger,提示InvalidOperationException: Can't use schemaId "\(B" for type "\)A.B". The same schemaId is already used for type "$A.B"

    这个问题是由多次对同一个类型Schema生成造成的。最常见的情况是你的控制器有方法不属于OData Routing的一部分(比如直接使用HttpGet指定),这样程序在扫描的过程中会重复对对象进行生成。解决办法有两种:
  1. 无法加载Swagger,提示System.MissingMethodException: Method not found: 'Microsoft.OData.ModelBuilder.Config.DefaultQuerySettings Microsoft.AspNetCore.OData.ODataOptions.get_QuerySettings()

    这个是版本问题,本人使用的OData版本在8.1.0,有一些破坏性更改,只要保持引用的OData版本<= 8.0.12就可以了。

    详细分析看这个MissingMethodException with OData v8.1.0 · Issue #980 · dotnet/aspnet-api-versioning (github.com)
  2. 找不到DescribeApiVersions()方法

    app找不到这个方法,大概率是在.NET 6的Minimal API之前的代码升级出现的,之前app是用IWebhostBuilder构建的,而现在的app是直接用过WebApplication构建得到的,含义不同,最简单的方法是改造一下,使用WebApplication重写一下Startup内容。

参考

武装你的WEBAPI-OData Versioning的更多相关文章

  1. OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service & Client

    一.概念介绍 1.1,什么是OData? 还是看OData官网的简单说明: An open protocol to allow the creation and consumption of quer ...

  2. AspNet WebApi OData 学习

    OData介绍:是一个查询和更新数据的Web协议.OData应用了web技术如HTTP.Atom发布协议(AtomPub)和JSON等来提供对不同应用程序,服务 和存储的信息访问.除了提供一些基本的操 ...

  3. AspNet.WebAPI.OData.ODataPQ

    AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务 AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔) AspNet. ...

  4. AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔)

    AspNet.WebAPI.OData.ODataPQ 这是针对 Asp.net WebAPI OData 协议下,查询分页.或者是说 本人在使用Asp.Net webAPI 做服务接口时写的一个分页 ...

  5. 主攻ASP.NET MVC4.0之重生:Asp.Net MVC WebApi OData

    1.新建MVC项目,安装OData Install-Package Microsoft.AspNet.WebApi.OData -Version 4.0.0 2.新建WebAPI Controller ...

  6. AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔)(转)

    出处:http://www.bubuko.com/infodetail-827612.html AspNet.WebAPI.OData.ODataPQ 这是针对 Asp.net WebAPI ODat ...

  7. [转]Composite Keys With WebApi OData

    本文转自:http://chris.eldredge.io/blog/2014/04/24/Composite-Keys/ In our basic configuration we told the ...

  8. [转]OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service & Client

    本文转自:http://www.cnblogs.com/bluedoctor/p/4384659.html 一.概念介绍 1.1,什么是OData? 还是看OData官网的简单说明: An open ...

  9. webAPi OData的使用

    一.OData介绍 开放数据协议(Open Data Protocol,缩写OData)是一种描述如何创建和访问Restful服务的OASIS标准. 二.OData 在asp.net mvc中的用法 ...

  10. 基于Angular+WebAPI+OData的增删改查

    对于在ASP.NET WebAPI中怎么使用OData,已经在我前面的日志中的说明, 在ASP.NET Web API中使用OData 在这个示例中.我新建了一个Order的实体,在前端使用Angul ...

随机推荐

  1. openssl 全面支持国密SM2/SM3/SM4加密算法

    sm4展示 代码 /** 文件名: https://github.com/liuqun/openssl-sm4-demo/blob/cmake/src/main.c */ #include <s ...

  2. P5192 有源汇上下界最大流总结

    之前听学长讲解时,只听了大体思路就跑路了,没有听到具体细节.后面在考虑出度多的点具体向虚拟源点连边还是虚拟汇点连边时,只凭直觉直接向源点连边,然后就一直WA,直到后来中午听同学讲解才反应过来,白白浪费 ...

  3. 【picoCTF]cookies write up

    顾名思义,这一挑战涉及对cookie的简单操作.登录页面会显示一个搜索框,其中包含一个输入字段,用于检查您为其提供的 Cookie 类型. 点击链接,页面如下: 随便在框里输入内容,显示如下: 输出返 ...

  4. [BUUCTF]HCTF 2018WarmUp1 write up

    ctrl+U查看源代码, 如下: 访问提示中的source.php文件 发现显示了源码,且存在另一个PHP文件hint.php(提示.php),先查看文件内是否有信息 用file来传参,并且要绕过wh ...

  5. linux内存管理之malloc、kmalloc、kzalloc、vmalloc的区别

    1 用户空间申请内存的方式 1.1 函数原型 void *malloc(unsigned int num_bytes): 1.2 函数解释和说明 如果分配成功则返回指向被分配内存的指针(此存储区中的初 ...

  6. Java笔记第七弹

    案例:复制Java文件(打印流改进版) import java.io.*; public class Main{ public static void main(String[] args) thro ...

  7. Spark Catalyst 查询优化器原理

    这里我们讲解一下SparkSQL的优化器系统Catalyst,Catalyst本质就是一个SQL查询的优化器,而且和 大多数当前的大数据SQL处理引擎设计基本相同(Impala.Presto.Hive ...

  8. 【ACM算法竞赛日常训练】DAY1题解与分析

    DAY1 共四题: 月月查华华的手机:https://ac.nowcoder.com/acm/problem/23053 Rinne Loves Edges:https://ac.nowcoder.c ...

  9. vue-router面试题

    1.vue-router怎么重定向页面? 答:路由中配置redirect属性 2.vue-router怎么配置404页面? 答:path: '*' 是对的 但是应该放在最后一个 3.切换路由时,需要保 ...

  10. 智能且集成的端到端移动应用程序安全解决方案——Quixxi简介

    移动应用程序安全变得简单快捷 Quixxi 是一种智能且集成的端到端移动应用程序安全解决方案.这个强大的工具可供开发人员在几分钟内保护和监控任何移动应用程序. Quixxi Security 评估应用 ...