美文网首页ASP.NET Core见识录Amazing .NET.NET
自动给 Asp.Net Core WebApi 增加 ApiVe

自动给 Asp.Net Core WebApi 增加 ApiVe

作者: 天天向上卡索 | 来源:发表于2018-12-05 10:01 被阅读11次

    自动给 Asp.Net Core WebApi 增加 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
        }
    }
    

    分析源代码

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

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

        services.AddApiVersioning();
    

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

    ApiVersion 服务注册

    IServiceCollectionExtensions

    ApiVersionNetural

    apiversionneutral

    ApiVersionNeutralAttribute

    ApiVersionNeutralAttribute

    ApiVersionActionSelector

    apiVersionActionSelector

    ControllerApiVentionBuilder

    ControllerApiVentionBuilder

    总结如下:

    如果 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();
    

    End

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

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

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

    有问题欢迎联系~~

    相关文章

      网友评论

        本文标题:自动给 Asp.Net Core WebApi 增加 ApiVe

        本文链接:https://www.haomeiwen.com/subject/ancicqtx.html