将 JSON 解析为对象

本文关键字:对象 JSON | 更新日期: 2023-09-27 18:31:00

尝试从 Web 服务调用中获取结果以返回模型。我收到错误:无法将当前 JSON 数组(例如 [1,2,3])反序列化为类型"CI.Models.Schedule",因为该类型需要 JSON 对象(例如 {"name":"value"})才能正确反序列化。

public Schedule getCourseSchedule()
{
    var obj = new
    {
        States = new[] { new { State = "MX" } },
        Zip = "",
        Miles = "",
        PaginationStart = 1,
        PaginationLimit = 3
    };
    using (var client = new WebClient())
    {
        client.Headers[HttpRequestHeader.ContentType] = "apoplication/json";
        var url = "http://192.168.1.198:15014/ShoppingCart2/CourseSchedule";
        var json = JsonConvert.SerializeObject(obj);
        byte[] data = Encoding.UTF8.GetBytes(json);
        byte[] result = client.UploadData(url, data);
        string returnjson = Encoding.UTF8.GetString(result);
        Schedule sched = JsonConvert.DeserializeObject<Schedule>(returnjson);
        return sched;
    }
}

进度模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Globalization;
namespace CI.Models
{
    public class Schedule
    {
        public IEnumerable<Course> Courses { get; set; }
    }
    public class Course
    {
/*
JSON Data returned from web service:        
{
   "ProgramGroup":"MR",
   "ProgramCode":"RM",
   "EventCode":"20160901MXMR",
   "FormalDate":"September 1-2, 2016",
   "StartDate":"2016'/09'/01",
   "Price":5,
   "LocName":"WB Hotel",
   "LocAddress":"Av. Speedy Gonzales 220",
   "LocCity":"Monterrey",
   "LocState":"MX",
   "LocZipCode":null,
   "LicenseeURL":null,
   "AgendaURL":"NA",
   "SeatsAreAvailable":"2",
   "GeneralInfoHTML":"General Info goes here.",
   "GateKeeperHTML":null,
   "EventType":"SS",
   "TotalCourses":3
}
*/
        public string ProgramGroup { get; set; }
        public string ProgramCode { get; set; }
        public string EventCode { get; set; }
        public string FormalDate { get { return FormalDate; } set { FormalDate = convertFormalDateToSpanish(value); } }
        public string StartDate { get; set; }
        public double Price { get; set; }
        public string LocName { get; set; }
        public string LocAddress { get; set; }
        public string LocCity { get ; set; }
        public string LocState { get; set; }
        public string LocZipCode { get; set; }
        public string LicenseeURL { get; set; }
        public string AgendaURL { get { return AgendaURL; } set { AgendaURL = buildAgendaLink(value); } }
        public string SeatsAreAvailable { get; set; }
        public string GeneralInfoHTML { get; set; }
        public string GateKeeperHTML { get; set; }
        public string EventType { get; set; }
        public int TotalCourses { get; set; }
        public string convertFormalDateToSpanish(string val) 
        {
            DateTime TheDate = DateTime.Parse(StartDate);
            string[] FormalDate = val.Split(" ".ToCharArray());
            CultureInfo ci = new CultureInfo("es-ES");
            string _Date = FormalDate[1].Replace("-", " al ").Replace(",", "");
            string _Month = ci.TextInfo.ToTitleCase(TheDate.ToString("MMMM", ci));
            val = string.Concat(_Date, " ", _Month);
            return val;
        }
        private string buildAgendaLink(string val)
        {
            if (val.Trim() != "")
            {
                val = string.Concat("<a href='"/pdfs/", EventCode, "_Agenda.pdf'">Agenda</a>");
            }
            else
            {
                val = "Agenda";
            }
            return val;
        }
    }

}

将 JSON 解析为对象

您的服务器返回一个数组。试试吧

Course[] courses = JsonConvert.DeserializeObject<Course[]>(returnjson);

请注意,这不是您原始问题的答案,但我将其添加为答案,以便用一些实际代码解释我上面的评论。

代码的第一个问题是FormalDateAgendaUrl属性根本不起作用。访问它们将导致StackOverflowException,因为你基本上是递归地定义它们的。

属性只是两个单独的getter/setter方法的语法糖,所以通过编写以下内容:

public class Course
{
    public string FormalDate
    {
        get { return FormalDate; }
    }
}

你基本上是在写这个:

public class Course
{
    public string GetFormalDate()
    {
        // recursive call, with no terminating condition,
        // will infinitely call itself until there is no
        // more stack to store context data (and CLR
        // will then throw an exception)
        return GetFormalDate(); 
    }
}

要解决此问题,您需要添加一个实际的支持字段,例如:

public class Course
{
    private string _formalDate; // <-- this is a backing field;
    // and this property uses the backing field to read/store data
    public string FormalDate 
    { 
        get { return _formalDate; } 
        set { _formalDate = convertFormalDateToSpanish(value); } 
    }
}

此外,属性 getter 返回的值与通过 setter 设置的值不同的值是不常见的。换句话说,我永远不会期望从一堂课上做到这一点:

var course = new Course();
course.StartDate = "2016/09/01";
course.FormalDate = "September 1-2, 2016";
Console.WriteLine(course.FormalDate); // prints "1 al 2 Septiembre" ?

我宁愿将此功能移动到不同的类中,或者至少创建返回这些值的不同属性:

public class CourseInfo
{
    // this is now a "dumb" auto-implemented property
    // (no need for a backing field anymore)
    public string FormalDate { get; set; }
    // this read-only property returns the converted value
    public string LocalizedFormalDate
    {
        get 
        {
            return convertFormalDateToSpanish(FormalDate);
        }
    }
}