自动给 Asp.Net Core Api 增加 ApiVersionNeutral

自动给 Asp.Net Core Api 增加 ApiVersionNeutral

Intro

新增加一个 Controller 的时候,经常忘记在 Controller 上增加 ApiVersion ,结果就导致前端使用指定的 ApiVersion 访问的时候就会失败,不支持的 Api 版本。

错误信息如下:

{	
    "error": {	
        "code": "UnsupportedApiVersion",	
        "message": "The HTTP resource that matches the request URI 'http://localhost:5000/api/values' does not support the API version '1.2'.",	
        "innerError": null	
    }	
}

因此希望可以在没有设置 ApiVersion 的时候也可以响应前端特定版本号的请求,而微软提供了 ApiVersionNeutral 可以忽略版本,任意版本号均可访问,于是就想自动给没有设置 ApiVersion 的 Controller 自动设置 ApiVersionNeutral,下面就通过分析源码来实现自动设置 ApiVersionNeutral

分析源代码

Asp.Net Core ApiVersion 源码地址:https://github.com/Microsoft/aspnet-api-versioning

使用 ApiVersion 会在注册服务的地方注册 ApiVersion 相关的服务

    services.AddApiVersioning();

找到源码 会发现注册服务的时候把 mvc 默认的 ActionSelector 替换成了 ApiVersionActionSelector,然后查看 ApiVersionActionSelector 的源码,找到了以下几处关键代码

ApiVersion 服务注册

640?wx_fmt=png

ApiVersionNetural

640?wx_fmt=png

ApiVersionNeutralAttribute

640?wx_fmt=png

ApiVersionActionSelector

640?wx_fmt=png

ControllerApiVentionBuilder

640?wx_fmt=png

总结如下:

如果 Controller 的 Attribute 定义的有 ApiVersionNeutralAttribute 就会忽略 ApiVersion 的限制,即使没有使用 ApiVersion 或者使用任意一个 ApiVersion 都可以路由到 Action,都可以访问得到,也不会出现开篇提到的错误。

解决方案

可以自己实现一个 IControllerModelConvention,去给没有定义 ApiVersion 的控制器加 ApiVersionNeutralAttribute,实现代码如下:

public class ApiControllerVersionConvention : IControllerModelConvention	
{	
    public void Apply(ControllerModel controller)	
    {	
        if (!(controller.ControllerType.IsDefined(typeof(ApiVersionAttribute)) || controller.ControllerType.IsDefined(typeof(ApiVersionNeutralAttribute))))	
        {	
            if (controller.Attributes is List<object>	
                attributes)	
            {	
                attributes.Add(new ApiVersionNeutralAttribute());	
            }	
        }	
    }	
}

在注册 Mvc 服务的时候,配置 MvcOptions

services.AddMvc(options =>	
    {	
        options.Conventions.Add(new ApiControllerVersionConvention());	
    });

启动项目,这时候再访问原来因为没有定义 ApiVersion 的控制器下的路由,这时就不会再报错了,使用任意一个 ApiVersion 也都不会有问题了,问题解决啦~~~

扩展方法

为了方便使用,你也可以加一个扩展方法,在扩展方法里配置 MvcOptions,根据自己的需要,我觉得两种方式都 OK 的,扩展方法示例如下:

public static class MvcBuilderExtensions	
{	
    public static IMvcBuilder AddApiControllerVersion(this IMvcBuilder builder)	
    {	
        if (builder == null)	
        {	
            throw new ArgumentNullException(nameof(builder));	
        }	
        builder.Services.Configure<MvcOptions>(options=> options.Conventions.Add(new ApiControllerVersionConvention()));	
        return builder;	
    }	
}

使用的时候可以直接在 AddMvc 之后加上扩展方法就可以了

services.AddMvc()	
    .AddApiControllerVersion();

实现源码

源码很简单,主要是看源码分析的过程,源码地址:https://github.com/WeihanLi/AspNetCorePlayground/blob/master/TestWebApplication/Conventions/ApiControllerConvention.cs

现在 .net core 是开源的,有许多问题都可以通过查看源码得到答案,有问题多 Google ,多看 Github 上的 issue,多看源码,相信大部分问题都可以解决了。

End

问题解决,完美收官,最后还是要说一下,注意这个的使用情景,如果你要指定一个默认的 ApiVersion 有更好的方法,直接配置 ApiVersioningOptions 中的 DefaultApiVersion就可以了

services.AddApiVersioning(options =>	
    {	
        options.AssumeDefaultVersionWhenUnspecified = true;	
        options.DefaultApiVersion = ApiVersion.Default;	
    });

如果你的 ApiVersion 不定,可能有些 Api 的 ApiVersion 会经常变,可以使用这种方式。

有问题欢迎联系~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值