Restful Web Api参数作为int数组

时间:2016-08-24 08:29:46

标签: c# rest asp.net-web-api2

理想情况下,我希望获得以下格式的网址:

/api/categories/1,2,3...N/products

这将返回指定类别的所有产品。使用多个类别ID进行一次API调用可以节省几次数据库调用,从而提高性能。

我可以通过以下方式轻松实现这一点。

public HttpResponseMessage GetProducts(string categoryIdsCsv)
{
    // <1> Split and parse categoryIdsCsv
    // <2> Get products
}

然而,这看起来并不像一个干净的解决方案,并且可能违反SRP原则。我也尝试使用ModelBinder,但它会在查询字符串中添加参数。

问题:

  1. 有没有一种干净的方式来实现这样的URL结构?
  2. 或者是否有不同/更好的方法来检索多个类别的所有产品?
  3. 如果您需要进一步澄清,请与我们联系。

3 个答案:

答案 0 :(得分:1)

我刚刚找到了问题的答案。使用Route时,ModelBinder属性缺少参数。

[Route("api/categories/{categoryIds}/products")]
public HttpResponseMessage GetProducts([ModelBinder(typeof(CategoryIdsModelBinder))] CategoryIds categoryIds)
{
    // <2> Get products using categoryIds.Ids
}

CategoryIds将是

public class CategoryIds
{
    public List<int> Ids{ get; set; }
}

CategoryIdsModelBinder将是

public class CategoryIdsModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(CategoryIds))
            {
                return false;
            }

            var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (val == null)
            {
                return false;
            }

            var key = val.RawValue as string;
            if (key == null)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Wrong value type");
                return false;
            }

            var values = val.AttemptedValue.Split(',');
            var ids = new List<int>();
            foreach (var value in values)
            {
                int intValue;
                int.TryParse(value.Trim(), out intValue);
                if (intValue > 0)
                {
                    ids.Add(intValue);
                }
            }

            if (ids.Count > 0)
            {
                var result = new CategoryIds
                {
                    Ids= ids
                };

                bindingContext.Model = result;
                return true;
            }

            bindingContext.ModelState.AddModelError(
                bindingContext.ModelName, "Cannot convert value to Location");
            return false;
        }

答案 1 :(得分:0)

我们可以使用Post方法

[RoutePrefix(&#34; api / categories&#34;)]     公共类TestController     {         [HttpPost]         [路线(&#34; getProducts&#34;)]

    public HttpResponseMessage GetProducts ( HttpRequestMessage request )
    {
        HttpResponseMessage  message               = null;
        string               input                 = string.Empty;

        input  = request.Content.ReadAsStringAsync ().Result;
         var ids = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>> ( input );

    }
}

答案 2 :(得分:0)

不幸的是,Web API无法将您的数据解析为数组或开箱即用的某种自定义对象。

如果要将url param解析为数组,可以尝试:

  1. 编写您自己的路由约束,它将读取您的param并将其从字符串转换为ints / strings / whatever数组;

  2. 编写自定义类型转换器并将其与数据模型一起使用;

  3. 编写您的价值提供者,并将其与您的数据模型一起使用

  4. 使用参数绑定

  5. 此外,你总是可以使用查询参数,它永远不会破坏REST的原则:)

    请参阅有关herehere

    的详细信息

    希望有所帮助