翼度科技»论坛 编程开发 .net 查看内容

OData WebAPI实践-兼容OData集合响应

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
本文属于 OData 系列文章
引言

OData 是一个开放标准,已经在 oasis 组织标准化,因此我们可以在标准的官网查询到 OData 的标准请求与返回形式:OData JSON Format Version 4.01 (oasis-open.org)
针对不同的数据类型,输出返回的格式也不尽相同,涉及的内容非常多。日常使用 OData 的过程中,我们经常处理的是实体对象以及实体对象的集合。如果直接返回 IQueryable 用于 OData 查询,那么返回的数据大多是集合(数组/列表)。
  1. {
  2.     "@odata.context": "http://localhost:9000/api/v2/$metadata#Collection(Datum_AggDto)",
  3.     "@odata.count": 2,
  4.     "value": [
  5.         {
  6.             "timestamp": 1682294400000,
  7.             "max": 180.0,
  8.             "min": 152.0,
  9.             "avg": 161.7605633802817
  10.         },
  11.         {
  12.             "timestamp": 1682985600000,
  13.             "max": 281.0,
  14.             "min": 180.0,
  15.             "avg": 228.39583333333334
  16.         }]
  17. }
复制代码
这个数组对象也不是很纯粹,它被 value 封装,并且提供了 @odata.context 元数据链接。如果我们的 API 没有被 OData 路由解析,那么默认 WEBAPI 会返回一个纯粹的数组对象:
  1. [
  2. {
  3.         "timestamp": 1682294400000,
  4.         "max": 180.0,
  5.         "min": 152.0,
  6.         "avg": 161.7605633802817
  7. },
  8. {
  9.         "timestamp": 1682985600000,
  10.         "max": 281.0,
  11.         "min": 180.0,
  12.         "avg": 228.39583333333334
  13. }]
复制代码
假设我们的对外的数据接口不完全被 OData 路由,会导致前端访问的行为不一致:一些 API 可以直接解析,另外一些 API 则需要使用 value 封装后处理。
封装非 OData Route Mapping

由于 OData 有了标准,为了对外保持一致性,我们可以尝试在返回非 OData 路由 API 时,将原始数组对象进行封装。
单实体对象
  1.         [HttpGet("/api/v1/Current")]
  2.         [ProducesResponseType(typeof(DeviceDataDto), Status200OK)]
  3.         public IActionResult Current(string key)
  4.         {
  5.             key = key.Trim('\'');
  6.             var data = _context.DeviceData.Where(w => w.DeviceId == key).OrderByDescending(w => w.Timestamp).FirstOrDefault();
  7.             return Ok(_mapper.Map<DeviceDataDto>(datas));
  8.         }
复制代码
对于以上的代码,只返回单个实体对象,返回的形式与 OData 标准中返回单个实体对象的标准一致,因此不需要额外的转换操作。
  1. {
  2.         //OData 返回会多一个context,普通API不会有。
  3.         "@odata.context": "http://localhost:9000/api/v2/$metadata#Datum_AggDto",
  4.         "timestamp": 1682985600000,
  5.         "max": 281.0,
  6.         "min": 180.0,
  7.         "avg": 228.39583333333334
  8. }
复制代码
实体对象集合
  1.         [HttpGet("/api/v1")]
  2.         [ProducesResponseType(typeof(IEnumerable<DeviceDataDto>), Status200OK)]
  3.         public async Task<IActionResult> Get(string key)
  4.         {
  5.             key = key.Trim('\'');
  6.             return Ok(await _context.DeviceData.Where(w => w.DeviceId == key).ToListAsync());
  7.         }
复制代码
以上代码返回的类型是一个集合,并且被 OData 路由映射。我们使用 value 这个 key 对齐进行封装:
  1.         [HttpGet("/api/v1")]
  2.         [ProducesResponseType(typeof(IEnumerable<DeviceDataDto>), Status200OK)]
  3.         public async Task<IActionResult> Get(string key)
  4.         {
  5.             key = key.Trim('\'');
  6.             var datas = await _context.DeviceData.Where(w => w.DeviceId == key).ToListAsync();
  7.             var result = new { Value = datas };
  8.             return Ok(result);
  9.         }
复制代码
注意这个 Value 我使用的是大写,由于我启用了 camelCase,所以会自动转换为小写。这样前端访问 API 时,不论是否为 OData API 都可以访问 value 的值获取数组对象。

来源:https://www.cnblogs.com/podolski/archive/2023/05/15/17401695.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具