【问题标题】:Parse json from web request response从 Web 请求响应中解析 json
【发布时间】:2021-02-15 09:30:40
【问题描述】:

我正在尝试将 http web 响应解析为数组或其他东西,以便我可以处理这些信息。这是我得到的 json 响应(+ 更多,但我只是审查了格式):

{
    "meta": {
        "status": 200
    },
    "data": {
        "account": {
            "account_phone_number": "XXXXXXXX",
            "account_email": "MAIL@hotmail.com"
        },
        "user": {
            "id": "5f2b17e7836fc7010025aed3",
            "age": 23,
        }
    }
}

如何将“用户”中的“id”写入控制台或文本框?

这是我的网络请求:

private void button1_Click(object sender, EventArgs e)
{
    const string WEBSERVICE_URL = "url_here";
    try
    {
        var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL);
        if (webRequest != null)
        {
            webRequest.Method = "GET";
            webRequest.Timeout = 12000;
            webRequest.ContentType = "application/json";
            webRequest.Headers.Add("x-auth-token", "Auth_token");

            using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream())
            {
                using (System.IO.StreamReader sr = new System.IO.StreamReader(s))
                {
                    var jsonResponse = sr.ReadToEnd();
                    richTextBox1.AppendText(jsonResponse);
                }
            }
        }
    }
    catch (Exception ex)
    {
        richTextBox1.AppendText("No workie");
    }
}

我尝试了以下方法:

public class Test
{
   public string meta {get;set;}
   public string data {get;set;}
}

并尝试将 json 序列化为如下表:

JavaScriptSerializer js = new JavaScriptSerializer();
Test[] Tester = js.Deserialize<Test[]>(jsonResponse);
richTextBox1.AppendText(Tester);

但没有运气。任何人都可以在这里指出正确的方向吗?

【问题讨论】:

  • 您转到quicktype.io 并将您的 json 粘贴到那里。它为您创建表示 json 的类,甚至向您展示(在代码 cmets 中)如何使用它们。结束
  • @Asphaug 您需要来自响应的所有信息还是只需要user 对象的id
  • @PeterCsala 我知道我需要什么标签,例如,我需要idageuser 中。并且只有来自accountaccount_email
  • @Asphaug 你可以使用与JavaScriptSerializer 不同的序列化程序吗?还是您必须满足的约束条件?
  • @PeterCsala 我想我可以以任何可行的方式做到这一点。这只是我认为正确的解决方案。

标签: c# api httpwebrequest javascriptserializer


【解决方案1】:

如果您能够使用除JavaScriptSerializer 之外的其他序列化程序,那么您可以利用部分反序列化。

如果是 Json.NET(以前称为 Newtonsoft Json),您至少有两个选择:

SelectToken

JObject semiParsedData = JObject.Parse(jsonResponse);
string id = (string)semiParsedData.SelectToken("data.user.id");
int age = (int)semiaParsedData.SelectToken("data.user.age");
string email = (string)semiParsedData.SelectToken("data.account.account_email");
  • 通过调用Parse 方法,我们将获得一个半解析对象。
  • 在这个对象上,我们可以通过SelectToken 发出Json Path query
    • 语法类似于XPath,可用于检索任何 任意数据形成 XML。
    • 更准确地说是JPath
  • SelectToken 返回 JToken。从中您可以通过多种方式检索数据:
    • (string)semiParsedData.SelectToken("data.user.id")
    • semiParsedData.SelectToken("data.user.id").Value&lt;string&gt;()
    • semiParsedData.SelectToken("data.user.id").ToObject&lt;string&gt;()

参考资料:

indexer operator

JObject semiParsedData = JObject.Parse(jsonResponse);
JToken data = semiParsedData["data"];

JToken user = data["user"];
string id = (string)user["id"];
int age = (int)user["age"];

JToken account = data["account"];
string email = (string)account["account_email"];
  • JToken 定义了以下索引器操作符,这并不是真正有用:
public virtual JToken? this[object key]
{
    get => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
    set => throw new InvalidOperationException("Cannot set child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
}
  • 另一方面,它的派生类JObject 会覆盖它以使该功能有用:
    • JObject 派生自 JContainer,而 JContainer 派生自 JToken)。
public JToken? this[string propertyName]
{
    get
    {
        ValidationUtils.ArgumentNotNull(propertyName, nameof(propertyName));
        JProperty? property = Property(propertyName, StringComparison.Ordinal);
        return property?.Value;
    }
    set
    {
        JProperty? property = Property(propertyName, StringComparison.Ordinal);
        if (property != null)
        {
            property.Value = value!;
        }
        else
        {
#if HAVE_INOTIFY_PROPERTY_CHANGING
            OnPropertyChanging(propertyName);
#endif
            Add(propertyName, value);
            OnPropertyChanged(propertyName);
        }
    }
}
  • 这里Property 方法尝试从_properties 集合中获取请求的实体:
    • private readonly JPropertyKeyedCollection _properties

参考:

【讨论】:

  • 我现在可能完全是个菜鸟,但Exception thrown: 'System.ArgumentNullException' in Newtonsoft.Json.dllusing (System.IO.StreamReader sr = new System.IO.StreamReader(s)) { var jsonResponse = sr.ReadToEnd(); JObject semiParsedData = JObject.Parse(jsonResponse); JToken data = semiParsedData["data"]; JToken user = data["user"]; string id = (string)user["id"]; int age = (int)user["age"]; JToken account = data["account"]; string email = (string)account["account_email"]; Console.WriteLine(id); }
  • @Asphaug 能否请您调试一下以了解上述代码段的哪一行抛出了ArgumentNullException
  • int age = (int)user["age"]; System.ArgumentNullException: 'Value cannot be null. Arg_ParamName_Name'
  • 该死的,我把它删回正确的格式后拼错了。这确实有效!现在我需要了解发生了什么:o 谢谢!
  • @Asphaug 我已经扩展了我的答案,如果你有时间请检查一下。
【解决方案2】:

一切都是正确的,除了你的 Test

对于复杂的 JSON,使用 https://json2csharp.com/ 将 Json 转换为 C# 类

public class Meta    {
    public int status { get; set; } 
}

public class Account    {
    public string account_phone_number { get; set; } 
    public string account_email { get; set; } 
}

public class User    {
    public string id { get; set; } 
    public int age { get; set; } 
}

public class Data    {
    public Account account { get; set; } 
    public User user { get; set; } 
}

public class Root    {
    public Meta meta { get; set; } 
    public Data data { get; set; } 
}

然后使用它

JavaScriptSerializer js = new JavaScriptSerializer();
var Root = js.Deserialize<Root>(jsonResponse);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多