我正在关注article on Attribute Routing in Web API 2尝试通过URI发送数组:
[HttpPost("api/set/copy/{ids}")]
public HttpResponseMessage CopySet([FromUri]int[] ids)
这在使用基于约定的路由时起作用:
http://localhost:24144/api/set/copy/?ids=1&ids=2&ids=3
但是使用属性路由它不再有效 - 我找不到404。
如果我试试这个:
http://localhost:24144/api/set/copy/1
然后它工作 - 我得到一个包含一个元素的数组。
如何以这种方式使用属性路由?
答案 0 :(得分:13)
您注意到的行为与行动选择和行动选择更为相关。模型绑定而不是属性路由。
如果您希望“ID”来自查询字符串,那么请修改您的路由模板,如下所示(因为您定义它的方式会使uri路径中的'ID'成为必需的):
[HttpPost("api/set/copy")]
看看你的第二个问题,你是否希望接受uri内部的id列表,如api/set/copy/[1,2,3]
?如果是的话,我不认为web api内置了对这种模型绑定的支持。
你可以实现像下面这样的自定义参数绑定来实现它(我猜有其他更好的方法来实现这一点,比如通过模型绑定器和值提供者,但我不太了解它们......所以你可能需要探索这些选项):
[HttpPost("api/set/copy/{ids}")]
public HttpResponseMessage CopySet([CustomParamBinding]int[] ids)
示例:
[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)]
public class CustomParamBindingAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor paramDesc)
{
return new CustomParamBinding(paramDesc);
}
}
public class CustomParamBinding : HttpParameterBinding
{
public CustomParamBinding(HttpParameterDescriptor paramDesc) : base(paramDesc) { }
public override bool WillReadBody
{
get
{
return false;
}
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext,
CancellationToken cancellationToken)
{
//TODO: VALIDATION & ERROR CHECKS
string idsAsString = actionContext.Request.GetRouteData().Values["ids"].ToString();
idsAsString = idsAsString.Trim('[', ']');
IEnumerable<string> ids = idsAsString.Split(',');
ids = ids.Where(str => !string.IsNullOrEmpty(str));
IEnumerable<int> idList = ids.Select(strId =>
{
if (string.IsNullOrEmpty(strId)) return -1;
return Convert.ToInt32(strId);
}).ToArray();
SetValue(actionContext, idList);
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
return tcs.Task;
}
}