Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有复杂数组参数的Web API_C#_Asp.net Mvc_Asp.net Web Api - Fatal编程技术网

C# 具有复杂数组参数的Web 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

在这件事上需要帮助。我有一个WebAPI,可以接收多个ID作为参数。用户可以使用2个路由调用API:

第一条路线:

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)