C# System.Text.Json 在响应格式因请求中的标志而更改时进行反序列化

huangapple go评论112阅读模式
英文:

C# System.Text.Json Deserializing when the response format changes due to flags in the request

问题

我正在尝试使用C#和System.Text.Json来调用供应商的API。一些API调用允许在请求中添加标志,以在响应中添加部分内容。我不确定如何处理这些(因为我缺乏经验)。

如果数据格式不改变,我可以轻松地发送和接收标准类。但如何设计类来处理这些可能的部分呢?

以下是SearchItemsRequest的类。它包含一个SearchItemsRequestSpec,用于打包搜索项。SearchItemsRequestSpec.ItemType决定了返回数据的基本格式。SearchItemsRequest.Flags决定了将包括哪些部分的格式。

当执行该方法时,我目前硬编码为仅支持响应中的一种项目类型。

对于单位,可能的部分有:

在这里有一些可能的部分,其他项目类型有它们自己的部分集合。

如果这是基本的C#,我可以创建一个接口并传递它,但由于反序列化和可能缺少的部分,我肯定存在知识差距。我应该如何编写一个类来处理项目返回数据的所有可能排列呢?

英文:

I'm trying to consume a vendor's api using c# and System.Text.Json. Some API calls allow for flags in the request that add sections to the response. I'm not sure how to handle these (lack of experience).

I can send and receive no problem to standard classes if the format doesn't change. How do I design classes to handle these possible sections?

Following are the classes for a SearchItemsRequest. It contains a SearchItemsRequestSpec that bundles up the search terms. The SearchItemsRequestSpec.ItemType governs the base format of the data returned. The SearchItemsRequest.Flags governs the sections that will be included of that format.

  1. /// <summary>
  2. /// Constructor. Sets up for a new search that will return all items.
  3. /// </summary>
  4. public SearchItemsRequest()
  5. {
  6. Spec = new SearchItemsRequestSpec();
  7. Force = SearchItemsForce.NewSearch;
  8. Flags = 1; // basic response
  9. From = 0; // for new search use 0
  10. To = 0; // return all elements beginning from index specified in the “from” parameter
  11. }
  12. /// <summary>
  13. /// Search Specification
  14. /// </summary>
  15. [JsonPropertyName("spec")]
  16. public SearchItemsRequestSpec Spec { get; set; }
  17. /// <summary>
  18. /// 0 - if such search has been done, then return cached result, 1 - to do a new search
  19. /// </summary>
  20. [JsonPropertyName("force")]
  21. public SearchItemsForce Force { get; set; }
  22. /// <summary>
  23. /// Data flags for the response
  24. /// <para>
  25. /// The value of this parameter depends on item type; data formats of all item types and their flags are described in the chapter <see href="https://sdk.wialon.com/wiki/en/sidebar/remoteapi/apiref/format/format">Data format</see>
  26. /// </para>
  27. /// </summary>
  28. [JsonPropertyName("flags")]
  29. public long Flags { get; set; }
  30. /// <summary>
  31. /// index of the first returned item (for new search use 0)
  32. /// </summary>
  33. [JsonPropertyName("from")]
  34. public uint From { get; set; }
  35. /// <summary>
  36. /// index of the last returned item (if 0 - return all elements beginning from index specified in the “from” parameter)
  37. /// </summary>
  38. [JsonPropertyName("to")]
  39. public uint To { get; set; }
  40. }
  41. /// <summary>
  42. /// Search Criteria
  43. /// <para>
  44. /// <see cref="https://sdk.wialon.com/wiki/en/sidebar/remoteapi/apiref/core/search_items">Search Items API Ref</see>
  45. /// </para>
  46. /// <para>
  47. /// Multi-criteria search is possible<br/>
  48. /// {"itemsType":"avl_unit","propName":"sys_name,rel_user_creator_name","propValueMask":"Volvo*,chdi_test","sortType":"sys_name","propType":"sys_name,rel_user_creator_name","or_logic":0}
  49. /// </para>
  50. /// </summary>
  51. public class SearchItemsRequestSpec
  52. {
  53. /// <summary>
  54. /// Constructor. Defaults are to search for units by unique id
  55. /// </summary>
  56. public SearchItemsRequestSpec()
  57. {
  58. ItemsType = SearchItemsItemType.avl_unit;
  59. PropName = SearchItemsPropName.sys_unique_id;
  60. PropValueMask = string.Empty;
  61. SortType = SearchItemsPropName.sys_unique_id;
  62. PropType = SearchItemsPropType.property;
  63. OrLogic = SearchItemsOrLogic.Disabled;
  64. }
  65. [JsonPropertyName("itemsType")]
  66. public SearchItemsItemType ItemsType { get; set; }
  67. [JsonPropertyName("propName")]
  68. public SearchItemsPropName PropName { get; set; }
  69. [JsonPropertyName("propValueMask")]
  70. public string PropValueMask { get; set; }
  71. /// <summary>
  72. /// Uses the same enum as PropName. Not a typo
  73. /// </summary>
  74. [JsonPropertyName("sortType")]
  75. public SearchItemsPropName SortType { get; set; }
  76. [JsonPropertyName("propType")]
  77. public SearchItemsPropType PropType { get; set; }
  78. [JsonPropertyName("or_logic")]
  79. public SearchItemsOrLogic OrLogic { get; set; }
  80. }

When executing the method, I'm currently hardcoded to only support one item type in the response

  1. internal class SearchItemsResponse
  2. {
  3. [JsonPropertyName("searchSpec")]
  4. public SearchItemsResponseSpec SearchSpec { get; set; }
  5. [JsonPropertyName("dataFlags")]
  6. public uint DataFlags { get; set; }
  7. [JsonPropertyName("totalItemsCount")]
  8. public uint TotalItemsCount { get; set; }
  9. [JsonPropertyName("indexFrom")]
  10. public uint IndexFrom { get; set; }
  11. [JsonPropertyName("indexTo")]
  12. public uint IndexTo { get; set; }
  13. [JsonPropertyName("items")]
  14. public List<Item_UnitBasic> Items { get; set; } //basic data for unit only
  15. }

the possible sections for a unit are

  1. [Flags]
  2. internal enum UnitResponseFlags : long
  3. {
  4. BaseFlag = 1, // 0x00000001
  5. CustomProperties = 2, // 0x00000002
  6. BillingProperties = 4, // 0x00000004
  7. CustomFields = 8, // 0x00000008
  8. Image = 16, // 0x00000010
  9. Messages = 32, // 0x00000020
  10. GUID = 64, // 0x00000040
  11. AdministrativeFields = 128, // 0x00000080
  12. AdvancedProperties = 256, // 0x00000100
  13. AvailableForCurrentMomentCommands = 512, // 0x00000200
  14. LastMessageAndPosition = 1024, // 0x00000400
  15. Sensors = 4096, // 0x00001000
  16. Counters = 8192, // 0x00002000
  17. Maintenance = 32768, // 0x00008000
  18. UnitConfigurationInReports = 131072, // 0x00020000 - trip detector and fuel consumption
  19. ListAllPossibleCommandsForCurrentUnit = 524288, // 0x00080000
  20. MessageParameters = 1048576, // 0x00100000
  21. UnitConnectionStatus = 2097152, // 0x00200000
  22. Position = 4194304, // 0x00400000
  23. ProfileFields = 8388608, // 0x00800000
  24. SetAllPossibleFlags = 4611686018427387903 // 0x3FFFFFFFFFFFFFFF
  25. }

There's a few, and the other item types have their own collections of sections.

If this was basic c#, I'd create an interface and pass that around, but with the deserialization and the possible missing sections, I definitely have a knowledge gap. How do I write a class to handle all the possible permutations of returned data for an item?

答案1

得分: 0

你可以使用JsonDocument来处理那些不容易映射到静态模型的 JSON 数据。<br>
(不要忘记在完成后释放文档,因为它使用了池内存)

英文:

You can use JsonDocument for json that can not easily be mapped to a static model.<br>
(Don't forget to dispose the document when you are done with it as it uses pooled memory)

huangapple
  • 本文由 发表于 2023年3月7日 13:14:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75658255.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定