ASP.NET Web API重载/参数

时间:2017-05-13 19:09:57

标签: c# asp.net-web-api overloading variadic-functions

tl; dr 版本是:我是否可以为Web API方法模拟params /重载而无需实现自定义IHttpActionSelector

PARAMS

我很惊讶地发现Web API方法不支持params(从那以后opened an issue in probably the wrong place

[HttpPost]
[Route("Test")]
public IHttpActionResult Test([FromBody] params Int32[] values) {
    // ...
}

POST - [1,2,3]的有效负载按预期工作,但只是4会导致valuesnull

重载

所以我决定尝试方法重载。但是,这也不起作用。

[HttpPost]
[Route("Test")]
public IHttpActionResult Test([FromBody] Int32 value) {
    return this.Test(new[] { value });
}

[HttpPost]
[Route("Test")]
public IHttpActionResult Test([FromBody] Int32[] values) {
    // ...
}

无论有效载荷如何(预计,我猜)都抛出:

  

找到与请求匹配的多个操作:...

结论

看起来我必须尝试实现一个自定义IHttpActionSelector,但我想知道是否有任何魔法我错过了我可以使用?

1 个答案:

答案 0 :(得分:1)

  

我是否可以模拟Web API方法的params /重载而不必   实现自定义IHttpActionSelector

这是与模型相关的绑定问题。

引用HttpParameterBinding

创建了以下活页夹和属性。

public class ParamsAttribute : ParameterBindingAttribute {
    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter) {
        //Check to make sure that it is a params array
        if (parameter.ParameterType.IsArray &&
            parameter.GetCustomAttributes<ParamArrayAttribute>().Count() > 0) {
            return new ParamsParameterBinding(parameter);
        }
        return parameter.BindAsError("invalid params binding");
    }
}

public class ParamsParameterBinding : HttpParameterBinding {

    public ParamsParameterBinding(HttpParameterDescriptor descriptor)
        : base(descriptor) {

    }

    public override async Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) {
        var descriptor = this.Descriptor;
        var paramName = descriptor.ParameterName;
        var arrayType = descriptor.ParameterType;
        var elementType = arrayType.GetElementType();
        try {
            //can it be converted to array
            var obj = await actionContext.Request.Content.ReadAsAsync(arrayType);
            actionContext.ActionArguments[paramName] = obj;
            return;
        } catch { }
        try {
            //Check if single and wrap in array
            var obj = await actionContext.Request.Content.ReadAsAsync(elementType);
            var array = Array.CreateInstance(elementType, 1);
            array.SetValue(obj, 0);
            actionContext.ActionArguments[paramName] = array;
            return;
        } catch { }
    }
}

这允许以下内容接受在请求正文中发布的单个和多个值。

[HttpPost]
[Route("Test")]
public IHttpActionResult Test([Params] params Int32[] values) {
    // ...
}

POST - [1,2,3]的有效负载将按预期工作,只需4就会导致values[4]

绑定器现在尊重params修饰符,从而使端点能够接受给定参数的一个或多个。它也适用于非原始对象

[HttpPost]
[Route("Customers")]
public IHttpActionResult Test([Params] params Customer[] customers) {
    // do important stuff
}

这可以进一步改进,以将任何集合作为参数来接受单个或多个值,而不仅仅是params