3

我创建了一个带有版本控制的 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.0URL 进行测试,它工作正常。我将在现有项目中实现此功能。

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

{ "Message": "发生错误。",
"ExceptionMessage": "索引不能小于 0 或等于或大于集合中的项目数。\r\n
参数名称: index\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 request)\r\n 在 Microsoft.Web.Http.Dispatcher.ControllerSelectionContext.<>c__DisplayClass6_0.<.ctor>b__0()\r\n 在 System.Lazy 1.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:

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

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

  1. 我在 WebAPIConfig 文件中没有任何默认 API 路由。
  2. 我在控制器中更新 Route Prefix 和 Route

现在问题重现了。

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

更新 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);

    }
}

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

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

4

3 回答 3

3

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

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

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

于 2019-01-02T08:50:13.603 回答
2

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

有关更多详细信息,请参阅:https ://github.com/Microsoft/aspnet-api-versioning/issues/428 。

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

于 2019-01-03T21:00:43.150 回答
0

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

参考:Scott 关于路由的博客

services.AddApiVersioning(
    o =>
    {
        o.AssumeDefaultVersionWhenUnspecified = true );
        o.DefaultApiVersion = new ApiVersion("1.0");
    } );
于 2019-01-02T12:19:43.030 回答