Web Api 参数绑定:snake_case 到 camelCase
Web Api Parameter binding: snake_case to camelCase
我正在做一个新的 Web api 项目,我的方法/参数遵循标准的 c# 命名格式;方法名是PascalCase,参数是camelCase.
不幸的是,我刚刚发现已发布给客户的文档,其中所有参数均为 ruby/php 样式,具有 snake_case 类型参数名称。
return对象和POST对象很容易转换;我使用 crallen's code 的一个版本来替换默认的 Json 输入/输出,但是对于 GET 请求,似乎没有这么简单的答案。
我希望保持我的命名约定不变。有没有办法告诉活页夹自动将所有请求的 my_parameter 更改为 myParameter?我必须构建一个完全不同的活页夹吗?
例如,如果我将其作为方法签名:
[Route("~/api/Widgets")]
[ResponseType(typeof(Widget))]
public async Task<HttpResponseMessage> GetWidget(int widgetId, int groupId)
{
. . .
我希望能够在 URL
中使用它
https://myserver.com/api/Widgets?widget_id=12345&group_id=54321
我是否必须重新发明轮子才能让它发挥作用?我已经看到替换特定类型模型绑定器的示例,但在这个级别上没有看到。我最好只更改代码中的参数名称吗?
您可以通过使用重写 Request.RequestUri
然后调用基本选择器的自定义 ApiControllerActionSelector
来实现。
开始了:
首先,创建自定义选择器:
public class SnakeCaseActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var newUri = CreateNewUri(
controllerContext.Request.RequestUri,
controllerContext.Request.GetQueryNameValuePairs());
controllerContext.Request.RequestUri = newUri;
return base.SelectAction(controllerContext);
}
private Uri CreateNewUri(Uri requestUri, IEnumerable<KeyValuePair<string, string>> queryPairs)
{
var currentQuery = requestUri.Query;
var newQuery = ConvertQueryToCamelCase(queryPairs);
return new Uri(requestUri.ToString().Replace(currentQuery, newQuery));
}
private static string ConvertQueryToCamelCase(IEnumerable<KeyValuePair<string, string>> queryPairs)
{
queryPairs = queryPairs
.Select(x => new KeyValuePair<string, string>(x.Key.ToCamelCase(), x.Value));
return "?" + queryPairs
.Select(x => String.Format("{0}={1}", x.Key, x.Value))
.Aggregate((x, y) => x + "&" + y);
}
}
接下来,创建一些扩展以转换为驼峰大小写和大写单词:
public static class StringExtensions
{
public static string ToCamelCase(this string source)
{
var parts = source
.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
return parts
.First().ToLower() +
String.Join("", parts.Skip(1).Select(ToCapital));
}
public static string ToCapital(this string source)
{
return String.Format("{0}{1}", char.ToUpper(source[0]), source.Substring(1).ToLower());
}
}
最后将动作选择器添加到 WebApiConfig
:
config.Services.Replace(typeof(IHttpActionSelector), new SnakeCaseActionSelector());
我想提出一个使用自定义值提供程序工厂的替代解决方案:
- 源自
QueryStringValueProviderFactory
并覆盖 GetValueProvider
- 获取查询字符串对并相应地修改它们。
- Return
NameValuePairsValueProvider
的实例接受新修改的值。
- 将
HttpConfiguration.Services
中原来的QueryStringValueProviderFactory
换成你自己的
大致翻译为:
public class SnakeQueryStringValueProviderFactory : QueryStringValueProviderFactory
{
public override IValueProvider GetValueProvider( HttpActionContext actionContext )
{
var pairs = actionContext.ControllerContext.Request.GetQueryNameValuePairs();
// modify query string keys accordingly
// e.g. remove '_' from query string keys
// var newPairs = ...
return new NameValuePairsValueProvider( newPairs, CultureInfo.InvariantCulture );
}
}
以下应该改进,但你明白了。
config.Services.Remove(
typeof( ValueProviderFactory ),
config.Services.GetValueProviderFactories().First( f => f is QueryStringValueProviderFactory )
);
config.Services.Insert( typeof( ValueProviderFactory ), 0, new SnakeQueryStringValueProviderFactory() ); // should be first
venerik,我认为您的 CreateNewUri 方法可以通过使用 UriBuilder class 而不是直接字符串替换来改进。这意味着您不必将查询字符串与“?”连接起来。在您的 ConvertQueryToCamelCase 方法中。当尝试替换 URL 中包含编码符号(如空格、冒号、百分号等)的查询字符串时,它将解决此问题。
private Uri CreateNewUri(Uri requestUri, IEnumerable<KeyValuePair<string, string>> queryPairs)
{
var currentQuery = requestUri.Query;
var newQuery = ConvertQueryToCamelCase(queryPairs);
var builder = new UriBuilder(requestUri)
{
Query = newQuery;
};
return builder.Uri;
}
private static string ConvertQueryToCamelCase(IEnumerable<KeyValuePair<string, string>> queryPairs)
{
queryPairs = queryPairs
.Select(x => new KeyValuePair<string, string>(x.Key.ToCamelCase(), x.Value));
return queryPairs
.Select(x => String.Format("{0}={1}", x.Key, x.Value))
.Aggregate((x, y) => x + "&" + y);
}
我正在做一个新的 Web api 项目,我的方法/参数遵循标准的 c# 命名格式;方法名是PascalCase,参数是camelCase.
不幸的是,我刚刚发现已发布给客户的文档,其中所有参数均为 ruby/php 样式,具有 snake_case 类型参数名称。
return对象和POST对象很容易转换;我使用 crallen's code 的一个版本来替换默认的 Json 输入/输出,但是对于 GET 请求,似乎没有这么简单的答案。
我希望保持我的命名约定不变。有没有办法告诉活页夹自动将所有请求的 my_parameter 更改为 myParameter?我必须构建一个完全不同的活页夹吗?
例如,如果我将其作为方法签名:
[Route("~/api/Widgets")]
[ResponseType(typeof(Widget))]
public async Task<HttpResponseMessage> GetWidget(int widgetId, int groupId)
{
. . .
我希望能够在 URL
中使用它https://myserver.com/api/Widgets?widget_id=12345&group_id=54321
我是否必须重新发明轮子才能让它发挥作用?我已经看到替换特定类型模型绑定器的示例,但在这个级别上没有看到。我最好只更改代码中的参数名称吗?
您可以通过使用重写 Request.RequestUri
然后调用基本选择器的自定义 ApiControllerActionSelector
来实现。
开始了:
首先,创建自定义选择器:
public class SnakeCaseActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var newUri = CreateNewUri(
controllerContext.Request.RequestUri,
controllerContext.Request.GetQueryNameValuePairs());
controllerContext.Request.RequestUri = newUri;
return base.SelectAction(controllerContext);
}
private Uri CreateNewUri(Uri requestUri, IEnumerable<KeyValuePair<string, string>> queryPairs)
{
var currentQuery = requestUri.Query;
var newQuery = ConvertQueryToCamelCase(queryPairs);
return new Uri(requestUri.ToString().Replace(currentQuery, newQuery));
}
private static string ConvertQueryToCamelCase(IEnumerable<KeyValuePair<string, string>> queryPairs)
{
queryPairs = queryPairs
.Select(x => new KeyValuePair<string, string>(x.Key.ToCamelCase(), x.Value));
return "?" + queryPairs
.Select(x => String.Format("{0}={1}", x.Key, x.Value))
.Aggregate((x, y) => x + "&" + y);
}
}
接下来,创建一些扩展以转换为驼峰大小写和大写单词:
public static class StringExtensions
{
public static string ToCamelCase(this string source)
{
var parts = source
.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
return parts
.First().ToLower() +
String.Join("", parts.Skip(1).Select(ToCapital));
}
public static string ToCapital(this string source)
{
return String.Format("{0}{1}", char.ToUpper(source[0]), source.Substring(1).ToLower());
}
}
最后将动作选择器添加到 WebApiConfig
:
config.Services.Replace(typeof(IHttpActionSelector), new SnakeCaseActionSelector());
我想提出一个使用自定义值提供程序工厂的替代解决方案:
- 源自
QueryStringValueProviderFactory
并覆盖GetValueProvider
- 获取查询字符串对并相应地修改它们。
- Return
NameValuePairsValueProvider
的实例接受新修改的值。 - 将
HttpConfiguration.Services
中原来的QueryStringValueProviderFactory
换成你自己的
大致翻译为:
public class SnakeQueryStringValueProviderFactory : QueryStringValueProviderFactory
{
public override IValueProvider GetValueProvider( HttpActionContext actionContext )
{
var pairs = actionContext.ControllerContext.Request.GetQueryNameValuePairs();
// modify query string keys accordingly
// e.g. remove '_' from query string keys
// var newPairs = ...
return new NameValuePairsValueProvider( newPairs, CultureInfo.InvariantCulture );
}
}
以下应该改进,但你明白了。
config.Services.Remove(
typeof( ValueProviderFactory ),
config.Services.GetValueProviderFactories().First( f => f is QueryStringValueProviderFactory )
);
config.Services.Insert( typeof( ValueProviderFactory ), 0, new SnakeQueryStringValueProviderFactory() ); // should be first
venerik,我认为您的 CreateNewUri 方法可以通过使用 UriBuilder class 而不是直接字符串替换来改进。这意味着您不必将查询字符串与“?”连接起来。在您的 ConvertQueryToCamelCase 方法中。当尝试替换 URL 中包含编码符号(如空格、冒号、百分号等)的查询字符串时,它将解决此问题。
private Uri CreateNewUri(Uri requestUri, IEnumerable<KeyValuePair<string, string>> queryPairs)
{
var currentQuery = requestUri.Query;
var newQuery = ConvertQueryToCamelCase(queryPairs);
var builder = new UriBuilder(requestUri)
{
Query = newQuery;
};
return builder.Uri;
}
private static string ConvertQueryToCamelCase(IEnumerable<KeyValuePair<string, string>> queryPairs)
{
queryPairs = queryPairs
.Select(x => new KeyValuePair<string, string>(x.Key.ToCamelCase(), x.Value));
return queryPairs
.Select(x => String.Format("{0}={1}", x.Key, x.Value))
.Aggregate((x, y) => x + "&" + y);
}