【问题标题】:Sending multiple queries to a webapi controller向 webapi 控制器发送多个查询
【发布时间】:2025-12-15 00:20:08
【问题描述】:

webapi(除了 odata)有没有办法指定多个查询? 这是场景: 自定义存储过程。接受 2 个邮政编码,执行距离计算并返回距离 WebAPI 端点接受 zip 并调用 sproc。并返回一个距离 DTO 类 ZIPDistance { 公共字符串 Zip1, 公共字符串 Zip2, 公共字符串距离 }

此网址:“/api/ZipDistances?$select=Distance&$filter=Zip1 eq 13240 和 Zip2 eq 90210 在 ZipDistancesController 中,我们使用 ODataQueryOptions 从上述查询中提取参数,调用 sproc。 并返回上面的 DTO。

出于潜在的性能原因,要求上述端点以某种方式接受邮政编码对的集合,即集合 “ZIPDistance” DTO 代表我们需要调用上述存储过程的“对”拉链,循环遍历 DTO,调用存储过程。每个 DTO 并返回结果的 DTO 集合 这样客户端就可以进行一次 HTTP 调用而不是多次调用,并在 1 次调用中获得所有结果。

我知道的唯一方法是通过 POST 并传入代表邮政编码对的 ZIPDistances 集合 有效载荷,但这从根本上是违反 REST 的,因为现在我们将 POST 的语义含义更改为表示数据检索(即 GET)

问题是WEBAPI是否支持上述场景以及在不重载的情况下实现上述场景的最佳方式是什么 动词意义和引起混淆。

更新:

我已经设计出了一种可能的解决方案here 的原型,其中涉及将配对嵌入到 URL 中:

http://<host>/api/ZipDistances?$select=Distance&$filter=Pairs eq 'Zip1 eq 13240 and Zip2 eq 90210,Zip1 eq 13241 and Zip2 eq 90211'

以及对应的DTO:

 public class ZipDistanceDTO
    {
        public string ZipPairs { get; set; }
        public string Distance { get; set; }
    }

这将返回以下结果:

[{"ZipPairs":"'Zip1 eq 13240 and Zip2 eq 90210","Distance":"558"},
{"ZipPairs":"Zip1 eq 13241 and Zip2 eq 90211'","Distance":"558"}]

对此的评论/想法将不胜感激。

更新(2): 我发布了另一个原型here,它使用了查询资源

【问题讨论】:

  • 我不确定这是否是纯粹的 REST 做事方式,但是在具有复杂参数的 BI Web 应用程序/api 中,例如您所描述的,我使用的是 JSON 的 PUT对象从 API 服务器请求向下钻取查询。基础数据通过 GET 检索,但向下钻取是 PUT。向下钻取请求可以包含大量参数,包括范围,因此构建查询字符串 URL 变得有点混乱,特别是因为我手头已经有了对象。
  • @Jfrankcarr:这不是 REST 做事的方式。POST 旨在用于任何既不安全也不幂等的操作。通常,POST 将用于创建新资源和/或更改状态。参考:*.com/questions/46585/…
  • PUT 是幂等的,但不安全。使用 GET 的另一个问题是 IE(公司强制浏览器)在 GET 中只能处理 2048 个字符。当然,何时使用 GET、PUT 或 POST 是一个长期存在的争论:*.com/questions/630453/put-vs-post-in-rest
  • @jfrankcarr:下面 Liel 的回答似乎效果很好,而且是 RESTFUL。针对“xxxQuery”端点发布“ZipDistanceQuery”对象以获取 ID,并使用该 ID 针对“xxxQueryResult”端点发出 GET 以获取结果。
  • 我在当前项目中使用查询资源样式对象,但我使用的是 PUT 而不是 POST,因为请求中没有更改数据。我发现报告/BI 应用程序的一个棘手问题是它们不太适合通常的 CRUD 模式。

标签: rest asp.net-web-api


【解决方案1】:

使用多个邮政编码发出正确的 GET 请求就可以了。

然而,
另一种可能的 RESTfull 方式是使用 POST 创建一个“查询资源”对象,返回“查询资源 ID 号”,稍后将在单独的 GET 请求中使用该对象。

您正在创建已保存的查询,这对于重新查询也很有效。

【讨论】:

  • 您对生成 ResourceID 有什么建议吗?将资源添加到数据库是多余的,因为这些查询是暂时的。我正在使用内存缓存来存储指定时间间隔的查询,但是如果在负载平衡的情况下,这种方法将不起作用,其中客户端可以点击实例 A 来发布“查询”对象并点击实例 B 来获取结果
  • 好吧,如果你不能让 A 与 B 通信,那么我认为除了发布到数据库之外别无他法。顺便说一句,DB 也可以是共享内存空间、文件系统或其他某种通信方式。您确定查询将是暂时的吗?
  • 是的,查询将是暂时的,因为查询资源实际上代表了我们调用存储过程的 ZipDistanceDTO 的集合。没有真正需要将其保存在数据库中。此外,它还会影响性能。因为我们每次都需要进行一次数据库访问来存储和检索 DTO 的序列化表示,仅用于执行存储过程。对我来说似乎有点矫枉过正。另一种选择可能是使用分布式缓存?