我有一个ASP。NET Web API(版本4)REST服务,我需要传递一个整数数组。
下面是我的动作方法:
public IEnumerable<Category> GetCategories(int[] categoryIds){
// code to retrieve categories from database
}
这是我试过的网址:
/Categories?categoryids=1,2,3,4
我有一个ASP。NET Web API(版本4)REST服务,我需要传递一个整数数组。
下面是我的动作方法:
public IEnumerable<Category> GetCategories(int[] categoryIds){
// code to retrieve categories from database
}
这是我试过的网址:
/Categories?categoryids=1,2,3,4
当前回答
如果有人需要-通过POST而不是FromUri来实现相同或类似的事情(如删除),使用FromBody和客户端(JS/jQuery)格式参数为$。参数({":categoryids}, true)
c#:
public IHttpActionResult Remove([FromBody] int[] categoryIds)
jQuery:
$.ajax({
type: 'POST',
data: $.param({ '': categoryids }, true),
url: url,
//...
});
关于$。Param ({": categoryids}, true)是。net期望post正文包含urlencoded的值,如=1&=2&=3,不带参数名,不带括号。
其他回答
正如Filip W指出的那样,你可能不得不求助于这样的自定义模型绑定器(修改为绑定到实际的参数类型):
public IEnumerable<Category> GetCategories([ModelBinder(typeof(CommaDelimitedArrayModelBinder))]long[] categoryIds)
{
// do your thing
}
public class CommaDelimitedArrayModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var val = bindingContext.ValueProvider.GetValue(key);
if (val != null)
{
var s = val.AttemptedValue;
if (s != null)
{
var elementType = bindingContext.ModelType.GetElementType();
var converter = TypeDescriptor.GetConverter(elementType);
var values = Array.ConvertAll(s.Split(new[] { ","},StringSplitOptions.RemoveEmptyEntries),
x => { return converter.ConvertFromString(x != null ? x.Trim() : x); });
var typedValues = Array.CreateInstance(elementType, values.Length);
values.CopyTo(typedValues, 0);
bindingContext.Model = typedValues;
}
else
{
// change this line to null if you prefer nulls to empty arrays
bindingContext.Model = Array.CreateInstance(bindingContext.ModelType.GetElementType(), 0);
}
return true;
}
return false;
}
}
然后你可以说:
/类别?categoryids=1,2,3,4和ASP。NET Web API将正确绑定您的categoryIds数组。
我最近遇到了这个需求,我决定实现一个ActionFilter来处理这个问题。
public class ArrayInputAttribute : ActionFilterAttribute
{
private readonly string _parameterName;
public ArrayInputAttribute(string parameterName)
{
_parameterName = parameterName;
Separator = ',';
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.ContainsKey(_parameterName))
{
string parameters = string.Empty;
if (actionContext.ControllerContext.RouteData.Values.ContainsKey(_parameterName))
parameters = (string) actionContext.ControllerContext.RouteData.Values[_parameterName];
else if (actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName] != null)
parameters = actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName];
actionContext.ActionArguments[_parameterName] = parameters.Split(Separator).Select(int.Parse).ToArray();
}
}
public char Separator { get; set; }
}
我像这样应用它(注意,我使用'id',而不是'ids',因为这是如何在我的路由中指定的):
[ArrayInput("id", Separator = ';')]
public IEnumerable<Measure> Get(int[] id)
{
return id.Select(i => GetData(i));
}
public url是:
/api/Data/1;2;3;4
您可能必须对其进行重构以满足您的特定需求。
将方法类型设置为[HttpPost],创建一个有一个int[]参数的模型,并使用json post:
/* Model */
public class CategoryRequestModel
{
public int[] Categories { get; set; }
}
/* WebApi */
[HttpPost]
public HttpResponseMessage GetCategories(CategoryRequestModel model)
{
HttpResponseMessage resp = null;
try
{
var categories = //your code to get categories
resp = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch(Exception ex)
{
resp = Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
}
return resp;
}
/* jQuery */
var ajaxSettings = {
type: 'POST',
url: '/Categories',
data: JSON.serialize({Categories: [1,2,3,4]}),
contentType: 'application/json',
success: function(data, textStatus, jqXHR)
{
//get categories from data
}
};
$.ajax(ajaxSettings);
ASP。NET Core 2.0解决方案(Swagger Ready)
输入
DELETE /api/items/1,2
DELETE /api/items/1
Code
编写提供程序(MVC如何知道使用什么绑定器)
public class CustomBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(int[]) || context.Metadata.ModelType == typeof(List<int>))
{
return new BinderTypeModelBinder(typeof(CommaDelimitedArrayParameterBinder));
}
return null;
}
}
编写实际的绑定器(访问关于请求、操作、模型、类型等的各种信息)
public class CommaDelimitedArrayParameterBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var value = bindingContext.ActionContext.RouteData.Values[bindingContext.FieldName] as string;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
var ints = value?.Split(',').Select(int.Parse).ToArray();
bindingContext.Result = ModelBindingResult.Success(ints);
if(bindingContext.ModelType == typeof(List<int>))
{
bindingContext.Result = ModelBindingResult.Success(ints.ToList());
}
return Task.CompletedTask;
}
}
将它注册到MVC
services.AddMvc(options =>
{
// add custom binder to beginning of collection
options.ModelBinderProviders.Insert(0, new CustomBinderProvider());
});
示例使用与Swagger良好记录的控制器
/// <summary>
/// Deletes a list of items.
/// </summary>
/// <param name="itemIds">The list of unique identifiers for the items.</param>
/// <returns>The deleted item.</returns>
/// <response code="201">The item was successfully deleted.</response>
/// <response code="400">The item is invalid.</response>
[HttpDelete("{itemIds}", Name = ItemControllerRoute.DeleteItems)]
[ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(void), StatusCodes.Status404NotFound)]
public async Task Delete(List<int> itemIds)
=> await _itemAppService.RemoveRangeAsync(itemIds);
编辑:微软建议使用TypeConverter来代替这种方法。因此,按照下面海报的建议,用SchemaFilter记录您的自定义类型。
所有其他解决方案都需要大量的工作。我试图在HttpGet方法参数中使用IEnumerable<long>或long[],但我认为没有必要做所有的工作,只是为了使处理程序方法参数的签名long[]。我最终只是把它变成字符串,然后在处理程序中把它分开。我只说了一句。
public async Task<IActionResult> SomeHandler(string idsString)
{
var ids = idsString.Split(',').Select(x => long.Parse(x));
现在你可以传递这些数字
.../SomeHandler?idsString=123,456,789,012