【问题标题】:Deserialization error from RESTful API来自 RESTful API 的反序列化错误
【发布时间】:2018-07-05 07:09:30
【问题描述】:

收到错误提示

JsonReaderException: 解析值时遇到意外字符:M. Path ', line 0, position 0.

当尝试解析 JSON 响应时(不是全部,而是前几项,我在 xxxxxx 中更改了匿名):

{
  "total_count": 1091,
  "items": [
    {
      "hap": "retry_limit_reached",
      "message": "Retry limit reached. Dropped: postmaster@xxxxx.ca \u2192 hamnifold@cxxxxxxxxems.com 'REMINDER - Pattison Stampede BBQ (Jul 11, 2018)' No MX for crscranessystems.com Server response: 498 No MX for crscranessystems.com",
      "type": "error",
      "created_at": "Thu, 05 Jul 2018 06:45:48 GMT",
      "message_id": "20180704185046.1.F263522F7F8571FE@mxxxxxx.ca"
    },
    {
      "hap": "tempfailed",
      "message": "Will retry in 14400 seconds: postmaster@xxxxxxxx.ca \u2192 conor@xxxxxxxxxy.org 'REMINDER - Pattison Stampede BBQ (Jul 11, 2018)' No MX for greexxxxxxxy.org Server response: 498 No MX for grexxxxxxy.org",
      "type": "warn",
      "created_at": "Thu, 05 Jul 2018 06:45:17 GMT",
      "message_id": "20180704225015.1.E917B878FC275EE7@mxxxxxxx.ca"
    },
    {
      "hap": "opened",
      "message": "Opened: jordan@lixxxxxxxxs.com",
      "type": "info",
      "created_at": "Thu, 05 Jul 2018 06:45:15 GMT",
      "message_id": "20180704192612.1.856579D071F84CF8@xxxxxxx.ca"
    },
    {
      "hap": "tempfailed",
      "message": "Will retry in 14400 seconds: postmaster@mxxxxxxx.ca \u2192 ccrawford@xxxxxx.com 'SUBJECT' No MX for step-eps.com Server response: 498 No MX for stxxxxxx.com",
      "type": "warn",
      "created_at": "Thu, 05 Jul 2018 06:45:14 GMT",
      "message_id": "20180704225014.1.33D047AC8A685236@xxxxxxxxi.ca"
    },
    //...

这是我的代码的一部分:

if(response.IsSuccessStatusCode)
{
    ViewBag.Msg = "Success";
    var stresult = await response.Content.ReadAsStringAsync();                
    var flogs = JsonConvert.DeserializeObject<List<EmailLog>>(stresult);
    logs = flogs.ToList();
}

这是电子邮件日志模型:

public class EmailLog
{
    public string hap { get; set; }

    public string message { get; set; }

    public string type { get; set; }

    public string created_at { get; set; }

    public string message_id { get; set; }
}

这是我第一次使用 RESTful API 和 JSON,所以我可能会遗漏一些简单的东西。

编辑:

这是我发出 API 请求的完整控制器代码:

HttpClient client = new HttpClient();

            client.BaseAddress = new Uri("https://api:key-xxxxxxxxxxxxxxxxxxxxxxxxxxxx@api.mailgun.net/v3");

            List<EmailLog> logs = new List<EmailLog>();

            HttpResponseMessage response = await client.GetAsync("/mg.xxxxx.ca/log");
            if (response.IsSuccessStatusCode)
            {

                //    var stresult = await response.Content.ReadAsStringAsync();                
                //    var flogs = JsonConvert.DeserializeObject<List<EmailLog>>(stresult);
                //    logs = flogs.ToList();
                var json = await response.Content.ReadAsStringAsync();
                var jObject = JObject.Parse(json);
                if (jObject.ContainsKey("items"))
                {
                    ViewBag.Msg = "Success";
                    logs = jObject["items"].ToObject<List<EmailLog>>();
                }
                //var logs = JsonConvert.DeserializeObject<ApiResponse>(json);

            }

            else { ViewBag.Msg = "Fail"; }

            return View(logs);

【问题讨论】:

    标签: c# .net json asp.net-core .net-core


    【解决方案1】:

    问题是试图直接获取EmailLog 对象的列表,因为它们包含在您的 json 响应的“items”元素中。

    您可以通过使用包装类来解决它,例如:

    public class ApiResponse
    {
        [JsonProperty(PropertyName = "total_count")]
        public int TotalCount { get; set; }
        [JsonProperty(PropertyName = "items")]
        public List<EmailLog> Items { get; set; }
    }
    

    然后你就不需要使用列表来反序列化了:

    var flogs = JsonConvert.DeserializeObject<ApiResponse>(json);
    

    【讨论】:

      【解决方案2】:

      这是创建根对象的替代方法,如另一个答案中所述

      这种方法利用了 Json.Net 提供的 Linq To JSON,用于反序列化 JSON。

      if(response.IsSuccessStatusCode) {
          ViewBag.Msg = "Success";
          var json = await response.Content.ReadAsStringAsync();
          var jObject = JObject.Parse(json);
          if (jObject.ContainsKey("items"))
              logs = jObject["items"].ToObject<List<EmailLog>>();   
      }
      

      解析 JSON,只提取所需的密钥。

      这假设不需要"total_count" 的值,因此只提取items 的值。

      如果需要整个对象,那么定义一个根对象并反序列化将是更简单的方法,如 @Isma's answer 中所示

      更新

      根据讨论,您表示该服务当前正在返回

      "Mailgun Magnificent API"
      

      这将匹配试图解析 M 时抛出的无效字符异常,因为它显然不是格式正确的 JSON。

      查看 Mailgun 文档后,您使用的 URL 似乎只能在浏览器中使用,而不是用于 HttpClient 类。

      documentation explains 表示应使用 BASIC 授权提出请求

      例如。

      var myMailgunDomain = "https://api.mailgun.net/v3/mg.xxxxx.ca/";            
      var client = new HttpClient() {
          BaseAddress = new Uri(myMailgunDomain)
      };
      var apiKey = "api:key-xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
      var parameter = Convert.ToBase64String(Encoding.ASCII.GetBytes(apiKey));
      client.DefaultRequestHeaders
          .Authorization = new AuthenticationHeaderValue("Basic", parameter);
      HttpResponseMessage response = await client.GetAsync("log");
      //...
      

      【讨论】:

      • 这个答案更适合我的情况,谢谢
      • 仍然收到相同的错误消息,将尝试其他解决方案
      • @dave317 重新检查返回的 JSON 字符串,查看异常消息,发现字符串在字符串开头(位置 0)以无效字符开头,这会使字符串无效 JSON ,因此错误。确认返回的 JSON 是有效的 JSON。
      • 我该如何检查?如果我在浏览器中输入我的 Uri 和 Query,它会显示我粘贴到我上面的问题中的 JSON..
      • @dave317 你能展示更多请求数据的代码吗?我假设您使用的是HttpClient,而responseHttpResponseMessage
      猜你喜欢
      • 2015-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-10
      • 2019-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多