C# 具有复杂数组参数的Web API
在这件事上需要帮助。我有一个WebAPI,可以接收多个ID作为参数。用户可以使用2个路由调用API: 第一条路线:C# 具有复杂数组参数的Web API,c#,asp.net-mvc,asp.net-web-api,C#,Asp.net Mvc,Asp.net Web Api,在这件事上需要帮助。我有一个WebAPI,可以接收多个ID作为参数。用户可以使用2个路由调用API: 第一条路线: api/{controller}/{action}/{ids} ex: http://localhost/api/{controller}/{action}/id1,id2,[...],idN 方法签名 public HttpResponseMessage MyFunction( string action, IList<string> value
api/{controller}/{action}/{ids}
ex: http://localhost/api/{controller}/{action}/id1,id2,[...],idN
方法签名
public HttpResponseMessage MyFunction(
string action,
IList<string> values)
假设:您实际上正在对数据执行一些命令
如果你的服务器负载比一个简单的路由更复杂,请考虑使用一个POST HTTP动词,并把它作为JSON发送给服务器,而不是把URI压缩成一个GET。 不同的假设:您正在执行复杂的fetch和GET,这对于RESTFUL服务来说是惯用的
使用查询字符串,根据@TrevorPilley发布的答案,您可以通过接受数组来处理它:
public HttpResponseMessage MyFunction(
string action,
string[] values)
将路线映射为:
api/{controller}/{action}
并使用查询字符串提供值:
GET http://server/api/Controller?values=1&values=2&values=3
对于自定义模型绑定器来说,这似乎是一个不错的方案。您可以处理传入数据并自行检测,然后将其传递给您自己的类型以在控制器中使用。无需与内置类型进行斗争 看 从页面中选择要保留答案的选项,以便: 模型粘合剂 比类型转换器更灵活的选项是创建自定义 模型活页夹。使用模型活页夹,您可以访问 HTTP请求、操作描述和来自 路线数据 要创建模型绑定器,请实现IModelBinder接口。这 接口定义了一个方法,BindModel:
bool BindModel(HttpActionContext actionContext, ModelBindingContext
bindingContext);
这里是用于地质点对象的模型绑定器
public class GeoPointModelBinder : IModelBinder {
// List of known locations.
private static ConcurrentDictionary<string, GeoPoint> _locations
= new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase);
static GeoPointModelBinder()
{
_locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 };
_locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 };
_locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 };
}
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(GeoPoint))
{
return false;
}
ValueProviderResult val = bindingContext.ValueProvider.GetValue(
bindingContext.ModelName);
if (val == null)
{
return false;
}
string key = val.RawValue as string;
if (key == null)
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName, "Wrong value type");
return false;
}
GeoPoint result;
if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result))
{
bindingContext.Model = result;
return true;
}
bindingContext.ModelState.AddModelError(
bindingContext.ModelName, "Cannot convert value to Location");
return false;
} } A model binder gets raw input values from a value provider. This design separates two distinct functions:
你
还可以向类型添加[ModelBinder]属性。Web API将使用
该类型的所有参数的指定模型绑定器
[ModelBinder(typeof(GeoPointModelBinder))] public class GeoPoint {
// .... }
我找到了解决办法
首先,我创建了一个类来覆盖
KeyValuePair<string, string>
键入以添加第三个元素我知道它不是一对!。我也可以使用元组类型:
public sealed class KeyValuePair<TKey, TValue1, TValue2>
: IEquatable<KeyValuePair<TKey, TValue1, TValue2>>
要将此类型与参数一起使用,我创建一个
ActionFilterAttribute
分裂;url中的值和创建KeyValuePair第三个元素是可选的
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.ContainsKey(ParameterName))
{
var keyValuePairs = /* function to split parameters */;
actionContext.ActionArguments[ParameterName] =
keyValuePairs.Select(
x => x.Split(new[] { "," }, StringSplitOptions.None))
.Select(x => new KeyValuePair<string, string, string>(x[0], x[1], x.Length == 3 ? x[2] : string.Empty))
.ToList();
}
}
最后,我将操作属性过滤器添加到控制器路由并更改参数类型:
"api/{controller}/{values}"
ex: http://localhost/api/{controller}/id1;type1;param1,id2;type2,[...],idN;typeN;param3
[MyCustomFilter("ids")]
public HttpResponseMessage MyFunction(
IList<KeyValuePair<string, string, string>> ids)
我可以使用一些url解析技术,但ActionFilterAttribute很棒,代码最终也不会乱七八糟 是的,我知道,但是邮寄不是一个选择如果你真的只是想得到一些东西,我不建议你发帖子,这就是Web API的一个要点,就是这个动词有很重要的意义。@TrevorPilley对我来说,它听起来更像是一个命令,而不是一个简单的获取东西。问题在于获取一组复杂的参数并在该列表上执行MyFunction。我想我应该明确地说明这个假设。@JonathanAnctil..您可以使用消息正文发送带有GET请求的内容,这不是推荐的方式,但如果查询字符串变得复杂,并且无法进行POST,您可以使用它。太有趣了!我将尝试您的解决方案:
public sealed class KeyValuePair<TKey, TValue1, TValue2>
: IEquatable<KeyValuePair<TKey, TValue1, TValue2>>
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.ContainsKey(ParameterName))
{
var keyValuePairs = /* function to split parameters */;
actionContext.ActionArguments[ParameterName] =
keyValuePairs.Select(
x => x.Split(new[] { "," }, StringSplitOptions.None))
.Select(x => new KeyValuePair<string, string, string>(x[0], x[1], x.Length == 3 ? x[2] : string.Empty))
.ToList();
}
}
"api/{controller}/{values}"
ex: http://localhost/api/{controller}/id1;type1;param1,id2;type2,[...],idN;typeN;param3
[MyCustomFilter("ids")]
public HttpResponseMessage MyFunction(
IList<KeyValuePair<string, string, string>> ids)