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

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

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.

    /// <summary>
    /// Constructor. Sets up for a new search that will return all items.
    /// </summary>
    public SearchItemsRequest()
    {
        Spec = new SearchItemsRequestSpec();
        Force = SearchItemsForce.NewSearch;
        Flags = 1;  // basic response
        From = 0;   // for new search use 0
        To = 0;     // return all elements beginning from index specified in the “from” parameter
    }

    /// <summary>
    /// Search Specification
    /// </summary>
    [JsonPropertyName("spec")]
    public SearchItemsRequestSpec Spec { get; set; }


    /// <summary>
    /// 0 - if such search has been done, then return cached result, 1 - to do a new search
    /// </summary>
    [JsonPropertyName("force")]
    public SearchItemsForce Force { get; set; }


    /// <summary>
    /// Data flags for the response
    /// <para>
    /// 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>
    /// </para>
    /// </summary>
    [JsonPropertyName("flags")]
    public long Flags { get; set; }


    /// <summary>
    /// index of the first returned item (for new search use 0)
    /// </summary>
    [JsonPropertyName("from")]
    public uint From { get; set; }


    /// <summary>
    /// index of the last returned item (if 0 - return all elements beginning from index specified in the “from” parameter)
    /// </summary>
    [JsonPropertyName("to")]
    public uint To { get; set; }
}


/// <summary>
/// Search Criteria
/// <para>
/// <see cref="https://sdk.wialon.com/wiki/en/sidebar/remoteapi/apiref/core/search_items">Search Items API Ref</see>
/// </para>
/// <para>
/// Multi-criteria search is possible<br/>
/// {"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}
/// </para>
/// </summary>
public class SearchItemsRequestSpec
{
    /// <summary>
    /// Constructor.  Defaults are to search for units by unique id
    /// </summary>
    public SearchItemsRequestSpec()
    {
        ItemsType = SearchItemsItemType.avl_unit;
        PropName = SearchItemsPropName.sys_unique_id;
        PropValueMask = string.Empty;
        SortType = SearchItemsPropName.sys_unique_id;
        PropType = SearchItemsPropType.property;
        OrLogic = SearchItemsOrLogic.Disabled;
    }

    [JsonPropertyName("itemsType")]
    public SearchItemsItemType ItemsType { get; set; }

    [JsonPropertyName("propName")]
    public SearchItemsPropName PropName { get; set; }

    [JsonPropertyName("propValueMask")]
    public string PropValueMask { get; set; }

    /// <summary>
    /// Uses the same enum as PropName.  Not a typo
    /// </summary>
    [JsonPropertyName("sortType")]
    public SearchItemsPropName SortType { get; set; }

    [JsonPropertyName("propType")]
    public SearchItemsPropType PropType { get; set; }

    [JsonPropertyName("or_logic")]
    public SearchItemsOrLogic OrLogic { get; set; }
}

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

internal class SearchItemsResponse
{
    [JsonPropertyName("searchSpec")]
    public SearchItemsResponseSpec SearchSpec { get; set; }

    [JsonPropertyName("dataFlags")]
    public uint DataFlags { get; set; }

    [JsonPropertyName("totalItemsCount")]
    public uint TotalItemsCount { get; set; }

    [JsonPropertyName("indexFrom")]
    public uint IndexFrom { get; set; }

    [JsonPropertyName("indexTo")]
    public uint IndexTo { get; set; }

    [JsonPropertyName("items")]
    public List<Item_UnitBasic> Items { get; set; }  //basic data for unit only
}

the possible sections for a unit are

[Flags]
internal enum UnitResponseFlags : long
{
	
	BaseFlag                               = 1,	   		// 0x00000001
	CustomProperties                       = 2,	   		// 0x00000002
	BillingProperties                      = 4,	   		// 0x00000004
	CustomFields                           = 8,	   		// 0x00000008
	Image                                  = 16,	   	// 0x00000010
	Messages                               = 32,	   	// 0x00000020
	GUID                                   = 64,	   	// 0x00000040
	AdministrativeFields                   = 128,	   	// 0x00000080
	AdvancedProperties                     = 256,	   	// 0x00000100
	AvailableForCurrentMomentCommands      = 512,	   	// 0x00000200
	LastMessageAndPosition                 = 1024,		// 0x00000400
	Sensors                                = 4096,		// 0x00001000
	Counters                               = 8192,		// 0x00002000
	Maintenance                            = 32768,		// 0x00008000
	UnitConfigurationInReports             = 131072,	// 0x00020000 - trip detector and fuel consumption
	ListAllPossibleCommandsForCurrentUnit  = 524288,	// 0x00080000
	MessageParameters                      = 1048576,	// 0x00100000
	UnitConnectionStatus                   = 2097152,	// 0x00200000
	Position                               = 4194304,	// 0x00400000
	ProfileFields                          = 8388608,	// 0x00800000
	SetAllPossibleFlags                    = 4611686018427387903  //  0x3FFFFFFFFFFFFFFF
}

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:

确定