C# 将整数数组传递给 ASP.NET Web API?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9981330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 11:29:54  来源:igfitidea点击:

Pass an array of integers to ASP.NET Web API?

c#arraysrestasp.net-web-api

提问by Hemanshu Bhojak

I have an ASP.NET Web API (version 4) REST service where I need to pass an array of integers.

我有一个 ASP.NET Web API(版本 4)REST 服务,我需要在其中传递一个整数数组。

Here is my action method:

这是我的操作方法:

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

And this is the URL that I have tried:

这是我尝试过的网址:

/Categories?categoryids=1,2,3,4

采纳答案by Lavel

You just need to add [FromUri]before parameter, looks like:

你只需要[FromUri]在参数之前添加,看起来像:

GetCategories([FromUri] int[] categoryIds)

And send request:

并发送请求:

/Categories?categoryids=1&categoryids=2&categoryids=3 

回答by Naveen Vijay

You may try this code for you to take comma separated values / an array of values to get back a JSON from webAPI

您可以尝试使用此代码获取逗号分隔值/值数组以从 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; }
 } 

Output :

输出 :

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

回答by Steve Czetty

I recently came across this requirement myself, and I decided to implement an ActionFilterto handle this.

我最近自己遇到了这个要求,我决定实施一个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; }
}

I am applying it like so (note that I used 'id', not 'ids', as that is how it is specified in my route):

我是这样应用它的(请注意,我使用了“id”,而不是“ids”,因为这是我在路线中指定的方式):

[ArrayInput("id", Separator = ';')]
public IEnumerable<Measure> Get(int[] id)
{
    return id.Select(i => GetData(i));
}

And the public url would be:

公共网址将是:

/api/Data/1;2;3;4

You may have to refactor this to meet your specific needs.

您可能需要重构它以满足您的特定需求。

回答by Mrchief

As Filip Wpoints out, you might have to resort to a custom model binder like this (modified to bind to actual type of param):

正如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;
    }
}

And then you can say:

然后你可以说:

/Categories?categoryids=1,2,3,4and ASP.NET Web API will correctly bind your categoryIdsarray.

/Categories?categoryids=1,2,3,4和 ASP.NET Web API 将正确绑定您的categoryIds数组。

回答by Waninlezu

public class ArrayInputAttribute : ActionFilterAttribute
{
    private readonly string[] _ParameterNames;
    /// <summary>
    /// 
    /// </summary>
    public string Separator { get; set; }
    /// <summary>
    /// cons
    /// </summary>
    /// <param name="parameterName"></param>
    public ArrayInputAttribute(params string[] parameterName)
    {
        _ParameterNames = parameterName;
        Separator = ",";
    }

    /// <summary>
    /// 
    /// </summary>
    public void ProcessArrayInput(HttpActionContext actionContext, string parameterName)
    {
        if (actionContext.ActionArguments.ContainsKey(parameterName))
        {
            var parameterDescriptor = actionContext.ActionDescriptor.GetParameters().FirstOrDefault(p => p.ParameterName == parameterName);
            if (parameterDescriptor != null && parameterDescriptor.ParameterType.IsArray)
            {
                var type = parameterDescriptor.ParameterType.GetElementType();
                var parameters = String.Empty;
                if (actionContext.ControllerContext.RouteData.Values.ContainsKey(parameterName))
                {
                    parameters = (string)actionContext.ControllerContext.RouteData.Values[parameterName];
                }
                else
                {
                    var queryString = actionContext.ControllerContext.Request.RequestUri.ParseQueryString();
                    if (queryString[parameterName] != null)
                    {
                        parameters = queryString[parameterName];
                    }
                }

                var values = parameters.Split(new[] { Separator }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(TypeDescriptor.GetConverter(type).ConvertFromString).ToArray();
                var typedValues = Array.CreateInstance(type, values.Length);
                values.CopyTo(typedValues, 0);
                actionContext.ActionArguments[parameterName] = typedValues;
            }
        }
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        _ParameterNames.ForEach(parameterName => ProcessArrayInput(actionContext, parameterName));
    }
}

Usage:

用法:

    [HttpDelete]
    [ArrayInput("tagIDs")]
    [Route("api/v1/files/{fileID}/tags/{tagIDs}")]
    public HttpResponseMessage RemoveFileTags(Guid fileID, Guid[] tagIDs)
    {
        _FileRepository.RemoveFileTags(fileID, tagIDs);
        return Request.CreateResponse(HttpStatusCode.OK);
    }

Request uri

请求 uri

http://localhost/api/v1/files/2a9937c7-8201-59b7-bc8d-11a9178895d0/tags/BBA5CD5D-F07D-47A9-8DEE-D19F5FA65F63,BBA5CD5D-F07D-47A9-8DEE-D19F5FA65F63

回答by Sofija

In case someone would need - to achieve same or similar thing(like delete) via POSTinstead of FromUri, use FromBodyand on client side(JS/jQuery) format param as $.param({ '': categoryids }, true)

万一有人需要 - 实现相同或类似的事情(如删除)通过POST而不是FromUri,使用FromBody和在客户端(JS/jQuery)格式参数作为$.param({ '': categoryids }, true)

c#:

C#:

public IHttpActionResult Remove([FromBody] int[] categoryIds)

jQuery:

jQuery:

$.ajax({
        type: 'POST',
        data: $.param({ '': categoryids }, true),
        url: url,
//...
});

The thing with $.param({ '': categoryids }, true)is that it .net will expect post body to contain urlencoded value like =1&=2&=3without parameter name, and without brackets.

问题$.param({ '': categoryids }, true)在于它 .net 将期望 post body 包含 urlencoded 值,就像=1&=2&=3没有参数名称一样,没有括号。

回答by Vaibhav

If you want to list/ array of integers easiest way to do this is accept the comma(,) separated list of string and convert it to list of integers.Do not forgot to mention [FromUri] attriubte.your url look like:

如果要列出/整数数组,最简单的方法是接受逗号(,)分隔的字符串列表并将其转换为整数列表。不要忘记提及 [FromUri] 属性。您的 url 如下所示:

...?ID=71&accountID=1,2,3,289,56

...?ID=71&accountID=1,2,3,289,56

public HttpResponseMessage test([FromUri]int ID, [FromUri]string accountID)
{
    List<int> accountIdList = new List<int>();
    string[] arrAccountId = accountId.Split(new char[] { ',' });
    for (var i = 0; i < arrAccountId.Length; i++)
    {
        try
        {
           accountIdList.Add(Int32.Parse(arrAccountId[i]));
        }
        catch (Exception)
        {
        }
    }
}

回答by Timothy Dooling

I addressed this issue this way.

我是这样解决这个问题的。

I used a post message to the api to send the list of integers as data.

我使用向 api 发送消息将整数列表作为数据发送。

Then I returned the data as an ienumerable.

然后我将数据作为可枚举返回。

The sending code is as follows:

发送代码如下:

public override IEnumerable<Contact> Fill(IEnumerable<int> ids)
{
    IEnumerable<Contact> result = null;
    if (ids!=null&&ids.Count()>0)
    {
        try
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:49520/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                String _endPoint = "api/" + typeof(Contact).Name + "/ListArray";

                HttpResponseMessage response = client.PostAsJsonAsync<IEnumerable<int>>(_endPoint, ids).Result;
                response.EnsureSuccessStatusCode();
                if (response.IsSuccessStatusCode)
                {
                    result = JsonConvert.DeserializeObject<IEnumerable<Contact>>(response.Content.ReadAsStringAsync().Result);
                }

            }

        }
        catch (Exception)
        {

        }
    }
    return result;
}

The receiving code is as follows:

接收代码如下:

// POST api/<controller>
[HttpPost]
[ActionName("ListArray")]
public IEnumerable<Contact> Post([FromBody]IEnumerable<int> ids)
{
    IEnumerable<Contact> result = null;
    if (ids != null && ids.Count() > 0)
    {
        return contactRepository.Fill(ids);
    }
    return result;
}

It works just fine for one record or many records. The fill is an overloaded method using DapperExtensions:

它适用于一条记录或多条记录。填充是使用 DapperExtensions 的重载方法:

public override IEnumerable<Contact> Fill(IEnumerable<int> ids)
{
    IEnumerable<Contact> result = null;
    if (ids != null && ids.Count() > 0)
    {
        using (IDbConnection dbConnection = ConnectionProvider.OpenConnection())
        {
            dbConnection.Open();
            var predicate = Predicates.Field<Contact>(f => f.id, Operator.Eq, ids);
            result = dbConnection.GetList<Contact>(predicate);
            dbConnection.Close();
        }
    }
    return result;
}

This allows you to fetch data from a composite table (the id list), and then return the records you are really interested in from the target table.

这允许您从复合表(id 列表)中获取数据,然后从目标表中返回您真正感兴趣的记录。

You could do the same with a view, but this gives you a little more control and flexibility.

您可以对视图执行相同的操作,但这为您提供了更多的控制权和灵活性。

In addition, the details of what you are seeking from the database are not shown in the query string. You also do not have to convert from a csv file.

此外,您从数据库中查找的内容的详细信息不会显示在查询字符串中。您也不必从 csv 文件转换。

You have to keep in mind when using any tool like the web api 2.x interface is that the get, put, post, delete, head, etc., functions have a general use, but are not restricted to that use.

You have to keep in mind when using any tool like the web api 2.x interface is that the get, put, post, delete, head, etc., functions have a general use, but are not restricted to that use.

So, while post is generally used in a create context in the web api interface, it is not restricted to that use. It is a regularhtml call that can be used for any purpose permitted by html practice.

So, while post is generally used in a create context in the web api interface, it is not restricted to that use. It is a regularhtml call that can be used for any purpose permitted by html practice.

In addition, the details of what is going on are hidden from those "prying eyes" we hear so much about these days.

In addition, the details of what is going on are hidden from those "prying eyes" we hear so much about these days.

The flexibility in naming conventions in the web api 2.x interface and use of regular web calling means you send a call to the web api that misleads snoopers into thinking you are really doing something else. You can use "POST" to really retrieve data, for example.

The flexibility in naming conventions in the web api 2.x interface and use of regular web calling means you send a call to the web api that misleads snoopers into thinking you are really doing something else. You can use "POST" to really retrieve data, for example.

回答by codeMonkey

Make the method type [HttpPost], create a model that has one int[] parameter, and post with json:

Make the method type [HttpPost], create a model that has one int[] parameter, and post with json:

/* 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);

回答by Jignesh Variya

Easy way to send array params to web api

Easy way to send array params to web api

API

API

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

Jquery : send JSON object as request params

Jquery : send JSON object as request params

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

It will generate your request URL like ../api/categories/GetCategories?categoryIds=1&categoryIds=2&categoryIds=3&categoryIds=4

It will generate your request URL like ../api/categories/GetCategories?categoryIds=1&categoryIds=2&categoryIds=3&categoryIds=4