将 json 数组传递给 REST Web API
Posted
技术标签:
【中文标题】将 json 数组传递给 REST Web API【英文标题】:Passing a json array to a REST Web API 【发布时间】:2021-12-31 07:44:01 【问题描述】:这是一个两部分的问题。
-
我想将一个 int 值数组传递给我的 REST url,但我得到了一个内联约束异常。我尝试定义的路线如下
[Route("categories/categoryId:int/documenttypes/documentTypes:int[]")]
... ...
当被调用时,它看起来像这样:
api/categories/2/documenttypes/[2,3,4,5]
谁能指出我如何处理这个内联约束异常的正确方向。我找到了几篇文章,但似乎没有一篇文章适用于如何处理 int 值数组。
也许它不可行,我应该将其更改为 POST 请求,但我想我会先尝试使用 GET 或仅使用字符串参数,然后将另一个资源定义添加到我的 REST url,例如
api/config/categories/2/documenttypes/multi?doctype=[1,3,4]
根据 REST 标准,此事件是否可接受?
api/categories/2/documenttypes/[1,3,4]
我知道我可以将它作为查询字符串传递,但我遇到的问题是,如果我这样做,我最终会遇到 2 个端点冲突:
api/categories/2/documenttypes
无参数并返回给定类别的所有文档类型
api/categories/2/documenttypes?doctypes=[1,2,3]
当定义然后调用时,我得到一个错误,即有多个端点具有相同的定义,因此请求查看我是否可以以某种方式将其作为内联约束传递。
希望以上内容有意义。如果没有,请走开。谢谢
【问题讨论】:
【参考方案1】:我找出了需要更改的各个部分。
首先,我必须添加一个新的路由约束 (IHttpRouteConstraint
) 来处理作为 Web API REST 资源的一部分传递的新数据类型:
public class HttpRouteConstraintIntArray : IHttpRouteConstraint
public bool Match(HttpRequestMessage request, IHttpRoute route,
string parameterName, IDictionary<string, object> values,
HttpRouteDirection routeDirection)
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
var parameters = value.ToString()
.Replace("", string.Empty)
.Replace("", string.Empty)
.Replace("[", string.Empty)
.Replace("]", string.Empty);
var type = typeof(int);
var newvalues = parameters.Split(new[] "," ,
StringSplitOptions.RemoveEmptyEntries)
.Select(TypeDescriptor.GetConverter(type)
.ConvertFromString).ToArray();
var typedValues = Array.CreateInstance(type, newvalues.Length);
newvalues.CopyTo(typedValues, 0);
return true;
return false;
一旦我声明了这个新约束,我还必须在 WebApiConfig.cs 中注册它:
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("intarray",
typeof(HttpRouteConstraintIntArray));
config.MapHttpAttributeRoutes(constraintResolver);
但是一旦我做了这些 stanges,我又开始犯另一个错误:
the request contains an entity body but no Content-Type header
get request ....
为了解决这个错误,我不得不在端点定义中添加 [FromUri]:
[HttpGet] [Route("categories/categoryId:int/documenttypes/
documentTypeIds:intarray")]
public async Task<IHttpActionResult> GetDataByDocumentTypeIds(
int categoryId,[FromUri] int[] documentTypeIds)
现在上面已经通过了这两个错误,但由于某种原因,documentTypeIds 以数组的形式返回,但它只包含一个值而不是 3,例如它的值是 0 而不是 1,所以显然需要添加别的东西。
为了处理最后一个问题,我必须创建一个动作过滤器属性:
public class ArrayInputAttribute : ActionFilterAttribute
private readonly string[] _parameternames;
public string Separator get; set;
public ArrayInputAttribute(params string[] parameternames)
this._parameternames = parameternames;
Separator = "-";
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];
parameters = parameters.ToString()
.Replace("", string.Empty)
.Replace("", string.Empty)
.Replace("[", string.Empty)
.Replace("]", string.Empty);
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)
foreach (var parameterName in _parameternames)
ProcessArrayInput(actionContext, parameterName);
最后,我必须将属性添加到端点定义中:
[HttpGet]
[Route("categories/categoryId:int/documenttypes/
documentTypeIds:intarray")]
[ArrayInputAttribute("documentTypeIds", Separator = ",")]
public async Task<IHttpActionResult> GetDataByDocumentTypeIds(int categoryId,
[FromUri] int[] documentTypeIds)
几点说明:
为了在 *** 中半体面地显示,一些行被拆分,显然在 .NET studio 中不起作用
上面的代码是我在谷歌搜索后最终找到的几篇文章的组合。它们是:
-Pass an array of integers to ASP.NET Web API?
从表面上看,我什至可能不需要约束,我想我现在没有时间调查,因为我需要继续前进,我会在稍后尝试时发布更新。
Web API Attribute Routing Route Constraints
Web API Attribute Routing Route Constrains
希望以上内容对其他人有所帮助。
谢谢。
【讨论】:
【参考方案2】:假设动作是
[HttpGet("~/api/categories/id/documenttypes")]
public ActionResult GetDocs(int id, int[] doctype)
if(doctype.Length > 0)
....
else ...
使用这个网址
api/categories/2/documenttypes?doctype=2&doctype=3&doctype=4&doctype=5
【讨论】:
您错过了我说使用此方法存在重复冲突的部分,因为 2 个端点最终会拥有相同的路由 @Thierry 参数不会改变路线 稍后我会再次检查它,但是当我有 api/categories/2/documenttypes 时,它需要返回所有文档类型,并且当我指定 api/categories/2/documenttypes?doctype= 1&doctype=2 等...我应该只返回这些。是否只是检查是否提供了参数并基于此调用不同的服务函数的情况? @Thierry 我在代码中添加了数组检查 太棒了!我希望摆脱这个臃肿的代码:)以上是关于将 json 数组传递给 REST Web API的主要内容,如果未能解决你的问题,请参考以下文章
我可以将 JSON 传递给这个 REST API 调用吗?阿帕奇点燃
如何在 JAVA 中将 JSON 和文件传递给 REST API?