在 C# 中反序列化一个复杂的 JSON,Twitch Pubsub

Deserialize a complex JSON in C#, Twitch Pubsub

我从 Twitch Pubsub System.

的 Channel Points 事件中得到这个 Json 字符串
{
"type": "reward-redeemed",
"data": {
  "timestamp": "2019-11-12T01:29:34.98329743Z",
  "redemption": {
    "id": "9203c6f0-51b6-4d1d-a9ae-8eafdb0d6d47",
    "user": {
      "id": "30515034",
      "login": "davethecust",
      "display_name": "davethecust"
    },
    "channel_id": "30515034",
    "redeemed_at": "2019-12-11T18:52:53.128421623Z",
    "reward": {
      "id": "6ef17bb2-e5ae-432e-8b3f-5ac4dd774668",
      "channel_id": "30515034",
      "title": "hit a gleesh walk on stream",
      "prompt": "cleanside's finest \n",
      "cost": 10,
      "is_user_input_required": true,
      "is_sub_only": false,
      "image": {
        "url_1x": "https://static-cdn.jtvnw.net/custom-reward-images/30515034/6ef17bb2-e5ae-432e-8b3f-5ac4dd774668/7bcd9ca8-da17-42c9-800a-2f08832e5d4b/custom-1.png",
        "url_2x": "https://static-cdn.jtvnw.net/custom-reward-images/30515034/6ef17bb2-e5ae-432e-8b3f-5ac4dd774668/7bcd9ca8-da17-42c9-800a-2f08832e5d4b/custom-2.png",
        "url_4x": "https://static-cdn.jtvnw.net/custom-reward-images/30515034/6ef17bb2-e5ae-432e-8b3f-5ac4dd774668/7bcd9ca8-da17-42c9-800a-2f08832e5d4b/custom-4.png"
      },
      "default_image": {
        "url_1x": "https://static-cdn.jtvnw.net/custom-reward-images/default-1.png",
        "url_2x": "https://static-cdn.jtvnw.net/custom-reward-images/default-2.png",
        "url_4x": "https://static-cdn.jtvnw.net/custom-reward-images/default-4.png"
      },
      "background_color": "#00C7AC",
      "is_enabled": true,
      "is_paused": false,
      "is_in_stock": true,
      "max_per_stream": { "is_enabled": false, "max_per_stream": 0 },
      "should_redemptions_skip_request_queue": true
    },
    "user_input": "yeooo",
    "status": "FULFILLED"
    }
  }
}

我想将这个字符串转换成以下变量: 编辑:我用 Json2CSharp.com

更新了这些 Clases
public class User
    {
        public string id { get; set; }
        public string login { get; set; }
        public string display_name { get; set; }
    }

    public class Image
    {
        public string url_1x { get; set; }
        public string url_2x { get; set; }
        public string url_4x { get; set; }
    }

    public class DefaultImage
    {
        public string url_1x { get; set; }
        public string url_2x { get; set; }
        public string url_4x { get; set; }
    }

    public class MaxPerStream
    {
        public bool is_enabled { get; set; }
        public int max_per_stream { get; set; }
    }

    public class Reward
    {
        public string id { get; set; }
        public string channel_id { get; set; }
        public string title { get; set; }
        public string prompt { get; set; }
        public int cost { get; set; }
        public bool is_user_input_required { get; set; }
        public bool is_sub_only { get; set; }
        public Image image { get; set; }
        public DefaultImage default_image { get; set; }
        public string background_color { get; set; }
        public bool is_enabled { get; set; }
        public bool is_paused { get; set; }
        public bool is_in_stock { get; set; }
        public MaxPerStream max_per_stream { get; set; }
        public bool should_redemptions_skip_request_queue { get; set; }
    }

    public class Redemption
    {
        public string id { get; set; }
        public User user { get; set; }
        public string channel_id { get; set; }
        public string redeemed_at { get; set; }
        public Reward reward { get; set; }
        public string user_input { get; set; }
        public string status { get; set; }
    }

    public class Data
    {
        public string timestamp { get; set; }
        public Redemption redemption { get; set; }
    }

    public class Root
    {
        public string type { get; set; }
        public Data data { get; set; }
    }

我尝试了不同的方法来反序列化 Json 字符串,但没有任何效果。 我最后一次尝试如下:(已编辑)

private static void SocketMessage(object sender, MessageEventArgs e)
        {
            try
            {
                Console.WriteLine(e.Data);
                //string json = e.Data.Replace("\"{", "{").Replace("\", string.Empty);
                string json = e.Data;
                Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(json);
                Console.WriteLine(myDeserializedClass.data.redemption.reward.title);
            }
            catch(Exception ex)
            {
                Console.Write(ex);
            }
        }

.NET Framework 4.7.1

如果有人能帮助我,我将不胜感激:)

测试字符串:

{"type":"MESSAGE","data":{"topic":"channel-points-channel-v1.196174120","message":"{\"type\":\"reward-redeemed\",\"data\":{\"timestamp\":\"2021-01-04T13:36:47.746629895Z\",\"redemption\":{\"id\":\"c664b1d8-65a6-4fb9-bef0-7b90a5a3819d\",\"user\":{\"id\":\"196174120\",\"login\":\"p90ez\",\"display_name\":\"P90Ez\"},\"channel_id\":\"196174120\",\"redeemed_at\":\"2021-01-04T13:36:47.746629895Z\",\"reward\":{\"id\":\"0452f6cb-cb1c-4c8e-9978-7103d01b621a\",\"channel_id\":\"196174120\",\"title\":\"Willkommenssound\",\"prompt\":\"Du erhälst deinen eigenen Command mit einem Sound deiner Wahl (bitte mir den Link auf Discord etc. schicken)! Für non-Subs max 15 Sekunden, für Subs bis zu 30 Sekunden.\n(geklaut von PrideGaymer)\",\"cost\":15000,\"is_user_input_required\":false,\"is_sub_only\":false,\"image\":{\"url_1x\":\"https://static-cdn.jtvnw.net/custom-reward-images/196174120/0452f6cb-cb1c-4c8e-9978-7103d01b621a/3feba875-7151-45e8-8bf1-09d78e48baf1/custom-1.png\",\"url_2x\":\"https://static-cdn.jtvnw.net/custom-reward-images/196174120/0452f6cb-cb1c-4c8e-9978-7103d01b621a/3feba875-7151-45e8-8bf1-09d78e48baf1/custom-2.png\",\"url_4x\":\"https://static-cdn.jtvnw.net/custom-reward-images/196174120/0452f6cb-cb1c-4c8e-9978-7103d01b621a/3feba875-7151-45e8-8bf1-09d78e48baf1/custom-4.png\"},\"default_image\":{\"url_1x\":\"https://static-cdn.jtvnw.net/custom-reward-images/default-1.png\",\"url_2x\":\"https://static-cdn.jtvnw.net/custom-reward-images/default-2.png\",\"url_4x\":\"https://static-cdn.jtvnw.net/custom-reward-images/default-4.png\"},\"background_color\":\"#FF9138\",\"is_enabled\":true,\"is_paused\":false,\"is_in_stock\":true,\"max_per_stream\":{\"is_enabled\":false,\"max_per_stream\":0},\"should_redemptions_skip_request_queue\":true,\"template_id\":null,\"updated_for_indicator_at\":\"2020-02-04T23:20:28.600840418Z\",\"max_per_user_per_stream\":{\"is_enabled\":false,\"max_per_user_per_stream\":0},\"global_cooldown\":{\"is_enabled\":false,\"global_cooldown_seconds\":0},\"redemptions_redeemed_current_stream\":null,\"cooldown_expires_at\":null},\"status\":\"FULFILLED\"}}}"}}

开头的问题有很多不清楚的地方。 问题不明确,输入数据和期望没有正确解释。

后期发现问题中分享的JSON不是e.Data的值。

无论如何,开始解决真正的问题。

e.Data 本身是一个 JSON 字符串并且它有一个 child 属性 其中 in-turn 是一个 JSON 字符串。

因此,需要进行两次 JSON 反序列化。

第一级反序列化需要以下 classes。

public class MessageData
{
    public string topic { get; set; }
    public string message { get; set; }
}

public class DataRoot
{
    public string type { get; set; }
    public MessageData data { get; set; }
}

e.Data的字符串表示DataRootclass的JSON结构。所以你需要先反序列化 DataRoot object 如下。

var rootData = JsonConvert.DeserializeObject<DataRoot>(e.Data);

现在下一个 JSON(在问题中首先共享)在 rootData.data.message 属性 中可用。要反序列化它,您需要遵循 classes.

public class User
{
    public string id { get; set; }
    public string login { get; set; }
    public string display_name { get; set; }
}

public class Image
{
    public string url_1x { get; set; }
    public string url_2x { get; set; }
    public string url_4x { get; set; }
}

public class DefaultImage
{
    public string url_1x { get; set; }
    public string url_2x { get; set; }
    public string url_4x { get; set; }
}

public class MaxPerStream
{
    public bool is_enabled { get; set; }
    public int max_per_stream { get; set; }
}

public class Reward
{
    public string id { get; set; }
    public string channel_id { get; set; }
    public string title { get; set; }
    public string prompt { get; set; }
    public int cost { get; set; }
    public bool is_user_input_required { get; set; }
    public bool is_sub_only { get; set; }
    public Image image { get; set; }
    public DefaultImage default_image { get; set; }
    public string background_color { get; set; }
    public bool is_enabled { get; set; }
    public bool is_paused { get; set; }
    public bool is_in_stock { get; set; }
    public MaxPerStream max_per_stream { get; set; }
    public bool should_redemptions_skip_request_queue { get; set; }
}

public class Redemption
{
    public string id { get; set; }
    public User user { get; set; }
    public string channel_id { get; set; }
    public string redeemed_at { get; set; }
    public Reward reward { get; set; }
    public string user_input { get; set; }
    public string status { get; set; }
}

public class Data
{
    public string timestamp { get; set; }
    public Redemption redemption { get; set; }
}

public class Root
{
    public string type { get; set; }
    public Data data { get; set; }
}

rootData.data.message表示上面声明的Rootclass的JSON结构。所以你需要反序列化如下。

var json = rootData.data.message;
var myDeserializedClass = JsonConvert.DeserializeObject<Root>(json);

因此代码的最终版本如下所示。

private static void SocketMessage(object sender, MessageEventArgs e)
{
    try
    {
        var rootData = JsonConvert.DeserializeObject<DataRoot>(e.Data);

        var json = rootData.data.message;

        Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(json);
        Console.WriteLine(myDeserializedClass.data.redemption.reward.title);
    }
    catch(Exception ex)
    {
        Console.Write(ex);
    }
}

希望本文能帮助您解决问题。