是否可以在控制器的 ApiVersion 属性中包含下划线?
Is it possible to include an underscore in an ApiVersion attribute on a controller?
我继承了一个遗留的 WebAPI 系统,该系统目前在路由模式中使用下划线来表示版本。例如/api/1_0/account
、/api/1_1/account
等
我正在尝试更新自动生成的文档以使用 Swagger,但是使用具有包含下划线的 ApiVersion
属性的显式路由会导致异常。例如,这很好用:
[ApiVersion("1")]
但是这会引发异常:
[ApiVersion("1_0")] // < note '_0' here
[RoutePrefix("api/{version:apiVersion}/account")]
public class AccountController : ApiBaseController
{
// actions...
}
例外情况是:
FormatException: The specified API version status '_1' is invalid.
System.InvalidOperationException: 'Failed to compare two elements in the array.'
at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.InitializeControllerInfoCache()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.GetControllerMapping()
at System.Web.Http.Routing.AttributeRoutingMapper.AddRouteEntries(SubRouteCollection collector, HttpConfiguration configuration, IInlineConstraintResolver constraintResolver, IDirectRouteProvider directRouteProvider)
at System.Web.Http.Routing.AttributeRoutingMapper.<>c__DisplayClass1_1.b__1()
at System.Web.Http.Routing.RouteCollectionRoute.EnsureInitialized(Func`1 initializer)
at System.Web.Http.Routing.AttributeRoutingMapper.<>c__DisplayClass1_0.b__0(HttpConfiguration config)
at System.Web.Http.HttpConfiguration.EnsureInitialized()
at ProjectName.Startup.Configuration(IAppBuilder app) in E:\ProjectPath\Foo.cs:line 25
问题很明显,但是如何在版本属性值中包含下划线?这个问题令人困惑,因为我假设 class 的内部结构(在某些时候)将值解析为整数,但属性本身接受一个字符串......?那为什么会这样?
ApiVersion
class 有一个 ParsePattern
定义版本字符串的格式。
const string ParsePattern = @"^(\d{4}-\d{2}-\d{2})?\.?(\d{0,9})\.?(\d{0,9})\.?-?(.*)$";
模式不允许下划线。提供与预期模式不匹配的版本会导致 FormatException
.
来源:https://github.com/Microsoft/aspnet-api-versioning/blob/master/src/Common/ApiVersion.cs#L25
ASP.NET API Version Format 文档提供了更多信息(由@DavidG 提供)。
关于为什么这不起作用的一些附加信息。此包的 Microsoft.AspNet.WebApi.Versioning
package follows semantic versioning rules which require the separator between major and minor parts to be a period. See the rules。
通过一些技巧,可以获取 API 版本控制包来解析下划线。这是非常基本的代码,可能还没有准备好生产,但应该给你一个方向。您需要的第一件事是自定义路由约束(本质上是扯掉 the default one):
public class CustomApiVersionRouteConstraint : IHttpRouteConstraint
{
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
if (string.IsNullOrEmpty(parameterName))
{
return false;
}
var properties = request.ApiVersionProperties();
var versionString = "";
if (values.TryGetValue(parameterName, out object value))
{
//This is the real 'magic' here, just replacing the underscore with a period
versionString = ((string) value).Replace('_', '.');
properties.RawApiVersion = versionString;
}
else
{
return false;
}
if (ApiVersion.TryParse(versionString, out var requestedVersion))
{
properties.ApiVersion = requestedVersion;
return true;
}
return false;
}
}
并确保 Web API 正在使用新约束:
var constraintResolver = new DefaultInlineConstraintResolver()
{
ConstraintMap =
{
["apiVersion"] = typeof( CustomApiVersionRouteConstraint )
}
};
config.MapHttpAttributeRoutes(constraintResolver);
我看到所有的答案都集中在你标题中的问题上...
但是你的问题可能出在你的方法上,你提到:
...attempting to update the auto-generated documentation to use Swagger, however using explicit routing with ApiVersion
attributes which contain underscores leads to an exception.
也许简化属性,只使用RoutePrefix,像这样:
[RoutePrefix("api/1_0/account")]
public class AccountController : ApiController
Bamm,问题解决了...
剩下的就是在您的 SwaggerConfig 中配置 MultipleApiVersions
,简单吧?
需要一个例子看这里:MultiApiVersions/Swagger_Test/App_Start/SwaggerConfig.cs
这是文档的样子:
http://swagger-net-test-multiapiversions.azurewebsites.net/swagger/ui/index
我继承了一个遗留的 WebAPI 系统,该系统目前在路由模式中使用下划线来表示版本。例如/api/1_0/account
、/api/1_1/account
等
我正在尝试更新自动生成的文档以使用 Swagger,但是使用具有包含下划线的 ApiVersion
属性的显式路由会导致异常。例如,这很好用:
[ApiVersion("1")]
但是这会引发异常:
[ApiVersion("1_0")] // < note '_0' here
[RoutePrefix("api/{version:apiVersion}/account")]
public class AccountController : ApiBaseController
{
// actions...
}
例外情况是:
FormatException: The specified API version status '_1' is invalid.
System.InvalidOperationException: 'Failed to compare two elements in the array.'
at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.InitializeControllerInfoCache()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at Microsoft.Web.Http.Dispatcher.ApiVersionControllerSelector.GetControllerMapping()
at System.Web.Http.Routing.AttributeRoutingMapper.AddRouteEntries(SubRouteCollection collector, HttpConfiguration configuration, IInlineConstraintResolver constraintResolver, IDirectRouteProvider directRouteProvider)
at System.Web.Http.Routing.AttributeRoutingMapper.<>c__DisplayClass1_1.b__1()
at System.Web.Http.Routing.RouteCollectionRoute.EnsureInitialized(Func`1 initializer)
at System.Web.Http.Routing.AttributeRoutingMapper.<>c__DisplayClass1_0.b__0(HttpConfiguration config)
at System.Web.Http.HttpConfiguration.EnsureInitialized()
at ProjectName.Startup.Configuration(IAppBuilder app) in E:\ProjectPath\Foo.cs:line 25
问题很明显,但是如何在版本属性值中包含下划线?这个问题令人困惑,因为我假设 class 的内部结构(在某些时候)将值解析为整数,但属性本身接受一个字符串......?那为什么会这样?
ApiVersion
class 有一个 ParsePattern
定义版本字符串的格式。
const string ParsePattern = @"^(\d{4}-\d{2}-\d{2})?\.?(\d{0,9})\.?(\d{0,9})\.?-?(.*)$";
模式不允许下划线。提供与预期模式不匹配的版本会导致 FormatException
.
来源:https://github.com/Microsoft/aspnet-api-versioning/blob/master/src/Common/ApiVersion.cs#L25
ASP.NET API Version Format 文档提供了更多信息(由@DavidG 提供)。
关于为什么这不起作用的一些附加信息。此包的 Microsoft.AspNet.WebApi.Versioning
package follows semantic versioning rules which require the separator between major and minor parts to be a period. See the rules。
通过一些技巧,可以获取 API 版本控制包来解析下划线。这是非常基本的代码,可能还没有准备好生产,但应该给你一个方向。您需要的第一件事是自定义路由约束(本质上是扯掉 the default one):
public class CustomApiVersionRouteConstraint : IHttpRouteConstraint
{
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
if (string.IsNullOrEmpty(parameterName))
{
return false;
}
var properties = request.ApiVersionProperties();
var versionString = "";
if (values.TryGetValue(parameterName, out object value))
{
//This is the real 'magic' here, just replacing the underscore with a period
versionString = ((string) value).Replace('_', '.');
properties.RawApiVersion = versionString;
}
else
{
return false;
}
if (ApiVersion.TryParse(versionString, out var requestedVersion))
{
properties.ApiVersion = requestedVersion;
return true;
}
return false;
}
}
并确保 Web API 正在使用新约束:
var constraintResolver = new DefaultInlineConstraintResolver()
{
ConstraintMap =
{
["apiVersion"] = typeof( CustomApiVersionRouteConstraint )
}
};
config.MapHttpAttributeRoutes(constraintResolver);
我看到所有的答案都集中在你标题中的问题上...
但是你的问题可能出在你的方法上,你提到:
...attempting to update the auto-generated documentation to use Swagger, however using explicit routing with
ApiVersion
attributes which contain underscores leads to an exception.
也许简化属性,只使用RoutePrefix,像这样:
[RoutePrefix("api/1_0/account")]
public class AccountController : ApiController
Bamm,问题解决了...
剩下的就是在您的 SwaggerConfig 中配置 MultipleApiVersions
,简单吧?
需要一个例子看这里:MultiApiVersions/Swagger_Test/App_Start/SwaggerConfig.cs
这是文档的样子:
http://swagger-net-test-multiapiversions.azurewebsites.net/swagger/ui/index