Web-API版本控制与默认版本不兼容

3

我创建了一个版本化的Web API应用程序。我将使用Microsoft.AspNet.WebApi.Versioning包来完成此操作。

Web API配置:

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": " at System.Web.Http.WebHost.Routing.HostedHttpRouteCollection.get_Item(Int32 index)\r\n at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.GetControllerName(HttpRequestMessage request)\r\n at Microsoft.Web.Http.Dispatcher.ControllerSelectionContext.<>c__DisplayClass6_0.<.ctor>b__0()\r\n at System.Lazy`1.CreateValue()\r\n at System.Lazy`1.LazyInitValue()\r\n at System.Lazy`1.get_Value()\r\n at Microsoft.Web.Http.Dispatcher.ConventionRouteControllerSelector.SelectController(ControllerSelectionContext context)\r\n at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.SelectController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__15.MoveNext()" }
更新1:
经过讨论和一些帮助,我确认这个默认版本适用于传统的路由方式。
在使用属性路由时出现了问题,请检查我的更新代码。
1.在WebAPIConfig文件中没有默认的API路由。 2.我更新了控制器中的路由前缀和路由。
现在问题已经复现。
您还可以通过结合传统路由和属性来复现此问题。
更新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);

    }
}

它创建了一个新的HttpConfiugration,而不是使用我们现有的WebAPIConfig类。因此,我不知道它可能会影响其他功能。

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


这是MVC的路由配置。我们需要你的WebAPI的路由配置。如果没有更改,这很可能位于WebApiConfig.cs中。 - Marco
好的。所以只有我困惑了。实际上,我已经删除了默认路由行,因为我仅配置了属性路由。我现在已更新。如果我让您感到困惑,对不起。 - Akhil
嗯,没关系。你的路由配置看起来没问题。我现在可以安全地重现你的错误了。现在让我们找到解决方案。 - Marco
好的,谢谢。我尝试了所有指定的方法。如果仍然没有得到任何东西,似乎可以通过扩展ControllerSelector来实现。 - Akhil
是否有一个使用版本2的控制器,具有相同的路由前缀?例如 [RoutePrefix("api/users")]?因为这会导致我的本地项目出错。如果我删除第二个控制器或其路由前缀,则错误会消失。这是很自然的,因为对于两个不同的控制器,不能有两个相同的路由。 - Marco
显示剩余3条评论
3个回答

3

如果您未指定版本,则被视为未经版本控制。在这种情况下,您必须设置AssumeDefaultVersionWhenUnspecified属性,如果没有其他说明,则默认版本为"1.0",如果未指定任何版本:

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

这个功能的文档在这里:https://github.com/Microsoft/aspnet-api-versioning/wiki/Existing-Services-Quick-Start

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

2
这是一个经确认的bug,只会出现在基于原生IIS实现(比如非OWIN)的主机环境中。尽管HttpRouteCollection具有索引器,但由System.Web定义的HostedHttpRouteCollection并不支持它。它会抛出一般的ArgumentOutOfRangeException异常而不是抛出NotSupportedException异常。
更多信息请参见:https://github.com/Microsoft/aspnet-api-versioning/issues/428
解决方案已发布,并可在包版本3.0.1中获取。

谢谢。在3.0.1版本中正常工作。 - Akhil

0
你可以尝试设置默认版本号并配置中间件,在未指定版本号时使用它。
参考文献:Scott在路由方面的博客
services.AddApiVersioning(
    o =>
    {
        o.AssumeDefaultVersionWhenUnspecified = true );
        o.DefaultApiVersion = new ApiVersion("1.0");
    } );

那行不通,因为他的路由没有将日期时间用作版本属性。一个合适的重载应该是 new ApiVersion(1,0) - Marco
谢谢。但这不是问题所在。我认为这与路由有关。只有当我使用RoutePrefix和Route属性时,才会出现这个问题。我的意思是属性路由。 - Akhil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接