我有一个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,不带参数名,不带括号。

其他回答

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

你可以尝试这段代码来获取逗号分隔的值/一个值数组来从webAPI返回JSON

 public class CategoryController : ApiController
 {
     public List<Category> Get(String categoryIDs)
     {
         List<Category> categoryRepo = new List<Category>();

         String[] idRepo = categoryIDs.Split(',');

         foreach (var id in idRepo)
         {
             categoryRepo.Add(new Category()
             {
                 CategoryID = id,
                 CategoryName = String.Format("Category_{0}", id)
             });
         }
         return categoryRepo;
     }
 }

 public class Category
 {
     public String CategoryID { get; set; }
     public String CategoryName { get; set; }
 } 

输出:

[
{"CategoryID":"4","CategoryName":"Category_4"}, 
{"CategoryID":"5","CategoryName":"Category_5"}, 
{"CategoryID":"3","CategoryName":"Category_3"} 
]

简单的方法发送数组参数到web api

API

public IEnumerable<Category> GetCategories([FromUri]int[] categoryIds){
 // code to retrieve categories from database
}

Jquery:发送JSON对象作为请求参数

$.get('api/categories/GetCategories',{categoryIds:[1,2,3,4]}).done(function(response){
console.log(response);
//success response
});

它会生成你的请求URL . . / api /类别/ GetCategories吗?categoryid = 1 &categoryids = 2 &categoryids = 3 &categoryids = 4

我的解决方案是创建一个属性来验证字符串,它做了一堆额外的公共功能,包括regex验证,你可以使用它来检查数字,然后我根据需要转换为整数…

你可以这样使用:

public class MustBeListAndContainAttribute : ValidationAttribute
{
    private Regex regex = null;
    public bool RemoveDuplicates { get; }
    public string Separator { get; }
    public int MinimumItems { get; }
    public int MaximumItems { get; }

    public MustBeListAndContainAttribute(string regexEachItem,
        int minimumItems = 1,
        int maximumItems = 0,
        string separator = ",",
        bool removeDuplicates = false) : base()
    {
        this.MinimumItems = minimumItems;
        this.MaximumItems = maximumItems;
        this.Separator = separator;
        this.RemoveDuplicates = removeDuplicates;

        if (!string.IsNullOrEmpty(regexEachItem))
            regex = new Regex(regexEachItem, RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var listOfdValues = (value as List<string>)?[0];

        if (string.IsNullOrWhiteSpace(listOfdValues))
        {
            if (MinimumItems > 0)
                return new ValidationResult(this.ErrorMessage);
            else
                return null;
        };

        var list = new List<string>();

        list.AddRange(listOfdValues.Split(new[] { Separator }, System.StringSplitOptions.RemoveEmptyEntries));

        if (RemoveDuplicates) list = list.Distinct().ToList();

        var prop = validationContext.ObjectType.GetProperty(validationContext.MemberName);
        prop.SetValue(validationContext.ObjectInstance, list);
        value = list;

        if (regex != null)
            if (list.Any(c => string.IsNullOrWhiteSpace(c) || !regex.IsMatch(c)))
                return new ValidationResult(this.ErrorMessage);

        return null;
    }
}