本文介绍了Web API将整数数组传递给操作方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个网络api方法:

I have this web api method:

[HttpGet]
[Route("WorkPlanList/{clientsId}/{date:datetime}")]
public async Task<IHttpActionResult> WorkPlanList([FromUri]List<int> clientsId, [FromUri]DateTime date)
{

}

这是我用来调用上述操作方法的URI:

Here is URI that I use to call the action method above:

http://localhost/blabla/api/workPlan/WorkPlanList/5,4/2016-06-01

我在弧形括号上设置了断点,并且当clientsId值为0时,日期时间值已完美传递.

I set the break point on curved bracket and see date time value is passed perfect while clientsId value is 0.

有人知道为什么我在clientsId上得到0吗?

Any idea why I get 0 on clientsId?

推荐答案

您的问题引起了我的兴趣,因此我想提出一种比Nkosi提供的答案更通用的解决方案.虽然Nkosi的答案会起作用,但我不喜欢ModelBinder语法,也不喜欢为每种类型定义一个新的ModelBinder.我之前一直在使用ParameterBindingAttribute,并且非常喜欢语法,所以我想从这里开始.这使您可以定义[FromUri]或[FromBody]之类的语法.我还希望能够使用不同的数组"类型,例如int []或List或HashSet或最好的IEnumerable.

Your problem intrigued me so I wanted to come up with a solution that was a bit more generic than the answer Nkosi provided. While Nkosi's answer will work, I'm not a fan of the ModelBinder syntax as well as defining a new ModelBinder for each type. I've been playing around with ParameterBindingAttribute before and really like the syntax so I wanted to start with this. This allows you to define a [FromUri] or [FromBody] like syntax. I also wanted to be able to use different "array" types such as int[] or List or HashSet or best yet, IEnumerable.

第1步:创建HttpParameterBinding

Step 1: Create a HttpParameterBinding

第2步:创建ParameterBindingAttribute

Step 2: Create a ParameterBindingAttribute

第3步:将它们放在一起

Step 3: Put it all together

通过HttpParameterBinding,您可以通过设置actionContext的ActionArguments字典来解析任何RouteData并将它们传递给您的方法.您只需从HttpParameterBinding继承并重写ExecuteBindingAsync方法.如果需要,可以在此处引发异常,但是也可以让异常通过,如果该方法无法解析RouteData,则该方法将收到null.对于此示例,我正在创建一个由RouteData制成的数组的JSON字符串.既然我们知道Json.NET在解析数据类型方面很棒,那么使用它似乎很自然.这将解析RouteData以获取CSV值.这最适合整数或日期.

An HttpParameterBinding allows you to parse any RouteData and pass them to your methed by setting the actionContext's ActionArguments dictionary. You simply inherit from HttpParameterBinding and override the ExecuteBindingAsync method. You can throw exception here if you want, but you can also just let it flow through and the method will receive null if it wasn't able to parse the RouteData. For this example, I am creating a JSON string of an array made from the RouteData. Since we know Json.NET is amazing at parsing data types, it seemed natural to use it. This will parse the RouteData for a CSV value. This works best for ints or dates.

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata;
using Newtonsoft.Json;

public class CsvParameterBinding : HttpParameterBinding
{
    public CsvParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor)
    {
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        var paramName = this.Descriptor.ParameterName;

        var rawParamemterValue = actionContext.ControllerContext.RouteData.Values[paramName].ToString();

        var rawValues = rawParamemterValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

        //To convert the raw value int a true JSON array we need to make sure everything is quoted.
        var jsonString = $"[\"{string.Join("\",\"", rawValues)}\"]";

        try
        {
            var obj = JsonConvert.DeserializeObject(jsonString, this.Descriptor.ParameterType);

            actionContext.ActionArguments[paramName] = obj;
        }
        catch
        {
            //There was an error casting, the jsonString must be invalid.
            //Don't set anything and the action will just receive null.
        }

        return Task.FromResult<object>(null);
    }
}

ParameterBindingAttribute允许我们使用在方法签名中声明绑定权限的简洁语法.我决定我想使用[FromUriCsv]作为语法,以便适当地命名该类.唯一要重写的是GetBinding方法,在该方法中,我们连接了刚创建的CsvParameterBinding类.

A ParameterBindingAttribute allows us to use the clean syntax of declaring the binding right in the method signature. I decided I wanted to use [FromUriCsv] as the syntax so the class is named appropriately. The only thing to overrid is the GetBinding method in which we wire up the CsvParameterBinding class we just made.

using System.Web.Http;
using System.Web.Http.Controllers;

public class FromUriCsvAttribute : ParameterBindingAttribute
{
    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
    {
        return new CsvParameterBinding(parameter);
    }
}

现在将其放在控制器上并使用它.

Now to put it on the controller and use it.

[Route("WorkPlanList/{clientsId}/{date:datetime}")]
public async Task<IHttpActionResult> WorkPlanList([FromUriCsv] List<int> clientsId, [FromUri] DateTime date)
{
    //matches WorkPlanList/2,3,4/7-3-2016
}

[Route("WorkPlanList/{clientsId}")]
public async Task<IHttpActionResult> WorkPlanList([FromUriCsv] HashSet<int> clientsId)
{
    //matches WorkPlanList/2,3,4,5,2
    //clientsId will only contain 2,3,4,5 since it's a HashSet the extra 2 won't be included.
}

[Route("WorkPlanList/{clientsId}/{dates}")]
public async Task<IHttpActionResult> WorkPlanList([FromUriCsv] IEnumerable<int> clientsId, [FromUriCsv] IEnumerable<DateTime> dates)
{
    //matches WorkPlanList/2,3,4/5-2-16,6-17-16,7-3-2016
}

我真的很喜欢这是怎么变成它的.它对于整数和日期确实非常有效,但由于小数点的长度确实会增加它,因此用小数点表示失败.现在,这很好地解决了您的问题.如果需要十进制数字,则应该可以使用正则表达式或mvc样式路由来调整路由.为了将复杂类型从标头值中提取出来,我使用了与此类似的方法,该标头值在[FromHeader("headerName")]语法中非常有效.

I really liked how this turned it. It works really well for ints and dates, but failed with decimals because the period in the route really jacks it up. For now, this solves your problem very well. If decimal numbers are needed, the routing should be able to be tweaked using regex or mvc style routing. I've used a similar method to this in order to pull complex types out of header values which worked really well with [FromHeader("headerName")] syntax.

这篇关于Web API将整数数组传递给操作方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 09:41