首页 > 其他分享 >武装你的WEBAPI-OData Versioning

武装你的WEBAPI-OData Versioning

时间:2023-05-05 20:23:30浏览次数:62  
标签:WEBAPI builder app options api OData Versioning

本文属于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,builder,app,options,api,OData,Versioning
From: https://www.cnblogs.com/podolski/p/17375269.html

相关文章

  • WebAPi实现多文件上传,并附带参数
    1、目的及需求需要实现的效果为,通过WebAPI实现多文件上传功能,并且在上传时需要能附带文件说明参数,用于保存文件记录 2、参数说明这里先说明以下需要的文件说明参数类///<summary>///前端文件上传时参数数据///</summary>publicclassDistributionDat......
  • 常见问题——关于.net WebApi使用Swagger报错:HTTP Error 403.14 - Forbidden
    问题:.netWebApi项目使用Swagger报错:HTTPError403.14-Forbidden解放方案:换一个端口即可推荐——删除解决方案下的.vs文件夹,重新生成即可参考:https://stackoverflow.com/questions/34970088/swagger-gives-me-http-error-403-14-forbidden/53863456......
  • WebAPI中添加参数,并获取数据
    publicstaticstringPostData(DataTabledt,intm){stringstrPostData=ConfigurationManager.AppSettings["APIPost"].ToString();//"http://218.78.103.37:43333/api/pushData";//dt=newArich......
  • Data source is not a transactional CDS view [OData Exposure]
    一个朋友遇到问题:给ABAPCDSview添加OData.publish:true注解激活之后,期望自动生成OData服务,但是遇到错误消息:DatasourceisnotatransactionalCDSview[ODataExposure]SAP社区上有人问类似的问题:https://answers.sap.com/questions/78804/cds-view-annotati......
  • 如何在 .NET Core WebApi 中处理 MultipartFormDataContent 中的文件
    在上一篇文章(如何在.NETCoreWebApi中处理MultipartFormDataContent)中,我们有描述过如何以最简单的方式在.NETCoreWebApi中处理MultipartFormDataContent。基于框架层面的封装,我们可以快速的从Request.Form中分别拿到文件内容和文本内容,但是这些默认的解析方式都是建......
  • 如何在 .NET Core WebApi 中处理 MultipartFormDataContent
    最近在对某个后端服务做.NETCore升级时,里面使用了多处处理MultipartFormDataContent相关内容的代码。这些地方从.NETFramework迁移到.NETCore之后的代码改动较大,由于本身没有测试覆盖,导致在部署QA环境后引发了一些问题。这里做一个技术复盘。什么是MultipartForm......
  • Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not b
    最近在使用图片导出base64的时候遇到下面的报错我的代码如下letmyImage=newImage();myImage.src=imgSrcData;myImage.crossOrigin='Anonymous';网上查阅资料,都说给图片设置 crossOrigin值为 Anonymous就可以了,我这么设置,但是依然不行,后来才发现,设置这个crossO......
  • SAP OData 开发实战教程:从入门到提高
    @目录SEGW-GatewayServiceBuilder使用RestfulABAPProgramming编程模型(简称RAP)开发OData服务使用SAPCloudApplicationProgramming编程模型开发OData服务详细目录本教程根据笔者在SAP研究院工作多年的实战经验,计划通过300篇以上的文章篇幅,深入介绍SAP三......
  • 关于 Fiori 应用里 SAP UI5 前端开发和 SEGW 后台 OData 服务开发的工作量比值问题
    我的知识星球有朋友向我提问:Jerry您好!请问一个中等复杂度的FioriUI5应用,前端代码用freestyle方式纯自己写,后端用SEGW开发Odata服务,前后端的工作量的比值大概是多少?需考虑调试测试的时间。关于这个问题,首先我们得界定,什么算是一个中等复杂度的Fiori应用?从前台视角来看,......
  • 如何自行查找出 SAP ABAP 标准的 OData 服务返回数据的后台数据库表和表字段名称
    笔者的知识星球有朋友提问,询问如何查找一个SAPABAPOData服务,暴露出的字段到底来自SAPABAP后台哪些数据库表的哪些字段。要回答这个问题,需要综合运用到我们过去学过的包括ABAP后台程序单步调试的知识。本文我们还是通过之前使用过的SAPCRM标准的Fiori应用,MyAccoun......