Web-API 版本控制不适用于默认版本

Posted

技术标签:

【中文标题】Web-API 版本控制不适用于默认版本【英文标题】:Web-API Versioning not working with Default version 【发布时间】:2019-05-28 22:11:48 【问题描述】:

我创建了一个带有版本控制的 Web API 应用程序。我将使用Microsoft.AspNet.WebApi.Versioning 包来做到这一点。

Webapi配置:

public static class WebApiConfig

    public static void Register(HttpConfiguration config)
    
        // Web API configuration and services
        config.AddApiVersioning(o => 
            o.AssumeDefaultVersionWhenUnspecified = true;
        );
        // Web API routes
        config.MapHttpAttributeRoutes();

    

这里我的假设是如果我没有通过版本,默认情况下它会选择版本 1。

控制器代码:

[ApiVersion("1.0")]
[RoutePrefix("api/users")]
public class UserV1Controller : BaseController

    public UserV1Controller()
    
    

    [Route("all", Name = "UsersCollection")]
    public async Task<IHttpActionResult> GetAll()
    
        var items = await UnitOfWork.Users.GetPaged(x => x.OrderBy(y => y.Id), 1, 20);
        //Add mapping to DTO 
        return Ok(items);
    


如果我使用http://localhost:10280/api/users/all?api-version=1.0 URL 进行测试,它可以正常工作。我将在现有项目中实现此功能。

为了向后兼容,我尝试了http://localhost:10280/api/users/all URL。 它给了我以 500 作为状态码的以下错误。

"Message": "发生错误。", "ExceptionMessage": "索引不能小于 0 或等于或大于集合中的项目数。\r\n参数 名称:索引\r\n实际值为 0。", "ExceptionType": "System.ArgumentOutOfRangeException", "StackTrace": "在 System.Web.Http.WebHost.Routing.HostedHttpRouteCollection.get_Item(Int32 索引)\r\n 在 Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.GetControllerName(HttpRequestMessage 请求)\r\n 在 Microsoft.Web.Http.Dispatcher.ControllerSelectionContext.c__DisplayClass6_0.<.ctor>b__0()\r\n 在 System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n 在 System.Lazy`1.get_Value()\r\n 在 Microsoft.Web.Http.Dispatcher.ConventionRouteControllerSelector.SelectController(ControllerSelectionContext 上下文)\r\n 在 Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.SelectController(HttpRequestMessage 请求)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.d__15.MoveNext()"


更新 1:

经过讨论和一些帮助,我可以确认这个默认版本适用于传统路由。

使用属性路由时重现该问题。请检查我更新的代码。

    我在 WebAPIConfig 文件中没有任何默认 API 路由。 我在控制器中更新了路由前缀和路由

现在问题重现了。

您还可以通过结合常规和属性来重现该问题。

更新 2:

现在我注意到问题在于配置。如果我直接在 Owin 启动类中添加路由配置,它工作正常。

    public partial class Startup

    public void Configuration(IAppBuilder app)
    
        ConfigureAuth(app);
        var configuration = new System.Web.Http.HttpConfiguration();
        var httpServer = new System.Web.Http.HttpServer(configuration);

        // reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
        configuration.AddApiVersioning(options =>
        
            options.ReportApiVersions = true;
            options.AssumeDefaultVersionWhenUnspecified = true;
        );
        configuration.MapHttpAttributeRoutes();
        app.UseWebApi(httpServer);

    

它会创建新的 HttpConfiguration,而不是使用我们现有的 WebAPIConfig 类。所以我不知道它可能会影响任何其他功能

因此,如果我将 Owin 配置为使用 webaPI 而不是 Global.asax 中的 GlobalConfiguration.Configure(WebApiConfig.Register),它可以正常工作。

【问题讨论】:

这是 mvc 的路由配置。我们需要您的 webapi 的路由配置。如果不更改,这很可能位于 WebApiConfig.cs 中 好的。所以只有我糊涂了。实际上,我删除了默认路由线,因为我只为属性路由配置。我现在更新了。对不起,如果我让你感到困惑。 不。没关系。您的路线配置似乎没问题。我现在可以安全地重现您的错误。现在让我们为它找到一个解决方案 好的,谢谢。我尝试了所有指定的方式。如果没有得到任何东西似乎可以通过扩展 ControllerSelector 是否有使用版本 2 的控制器,具有相同的路由前缀?例如[RoutePrefix("api/users")]?因为这导致您在我的本地项目中出错。如果我删除第二个控制器或其路由前缀,错误就会消失。这是很自然的,因为 2 个不同的控制器不能有 2 个相同的路由。 【参考方案1】:

这是一个已确认的错误,仅当托管在普通 IIS 实现(例如非 OWIN)上时才会出现。尽管 HttpRouteCollection 具有索引器,但 System.Web 定义的 HostedHttpRouteCollection 不支持它。不是抛出 NotSupportedException,而是抛出一个通用的 ArgumentOutOfRangeException

更多详情请见:https://github.com/Microsoft/aspnet-api-versioning/issues/428。

该修复程序已包含在包版本3.0.1 中,现在可用。

【讨论】:

谢谢。在 3.0.1 版中按预期工作【参考方案2】:

您可以尝试设置默认版本号并配置中间件以在未指定版本号时使用它。

参考:Scott's blog on routing

services.AddApiVersioning(
    o =>
    
        o.AssumeDefaultVersionWhenUnspecified = true );
        o.DefaultApiVersion = new ApiVersion("1.0");
     );

【讨论】:

那行不通,因为他的路线不使用 DateTimes 作为版本属性。一个合适的重载应该是new ApiVersion(1,0) 谢谢。但这不是问题。我认为这与路由有关。当我仅使用 RoutePrefix 和 Route 属性时,会重现此问题。我的意思是属性路由【参考方案3】:

如果您未指定版本,则将其视为未版本化。在这种情况下,您必须设置 AssumeDefaultVersionWhenUnspecified 属性,如果没有另行说明,则假定默认版本为 "1.0",如果未指定:

config.AddApiVersioning(o => 
    o.AssumeDefaultVersionWhenUnspecified = true;
);

此功能在此处记录:https://github.com/Microsoft/aspnet-api-versioning/wiki/Existing-Services-Quick-Start

【讨论】:

没有。如果我明确提供 api 版本,我可以访问。我还尝试了文档中指定的相同示例,但出现了相同的错误。还有其他配置吗? 我的错,请使用您的路线配置编辑您的问题。我可以通过在操作方法上添加 [Route] 装饰器来重现您的错误。 您的问题中仍然缺少您的路线配置 我添加了 route.config 文件代码。由于这只是 API,我认为我们并不关心 route.config。正确的?我只关心 webApiConfig 文件 现在我更新了我的最新发现。但我不知道为什么会这样

以上是关于Web-API 版本控制不适用于默认版本的主要内容,如果未能解决你的问题,请参考以下文章

ipa 未安装在 iphone 上,因为它不适用于此版本的 ios

Spring MVC 和 Thymeleaf 资源版本控制

免费版本控制和问题跟踪系统[关闭]

Swashbuckle 版本控制选择默认的 API 版本出现在 Swagger

Git初识

用于版本控制外部 API 的 Java 包命名