简体   繁体   中英

How to deserialize json array in c#

I am trying to deserialize the following JSON file: http://komunikaty.tvp.pl/komunikatyxml/malopolskie/wszystkie/0?_format=json

My c# code:

MemoryStream stream1 = new MemoryStream();
StreamWriter writer = new StreamWriter(stream1);
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ApiRegionalne));
writer.Write(json);
writer.Flush();
stream1.Position = 0;
dane = (ApiRegionalne)ser.ReadObject(stream1);

And my classes:

[DataContract]
public class newses
{
    public int id;
    public string title;
    public bool shortcut;
    public string content;
    public bool rso_alarm;
    public string rso_icon;
    public string longitude;
    public string latitude;
    public int water_level_value;
    public int water_level_warning_status_value;
    public int water_level_alarm_status_value;
    public int water_level_trend;
    public string river_name;
    public string location_name;
    public string type;
}

[DataContract]
public class ApiRegionalne
{
    [DataMember(Name = "newses")]
    public newses[] newses;
}

The JSON deserializer doesn't throw any exceptions, but my data is nevertheless null.

What am I doing wrong?

You need to mark all of the public fields of class newses as being part of the contract:

[DataContract]
public class newses
{
    [DataMember(Name = "id")] //This is what you need to add
    public int id;

    //Do the same for all other fields        
}

Your basic problem is that the data contract serializers (both DataContractSerializer and DataContractJsonSerializer ) are opt-in . If you mark a type with [DataContract] you must also mark the members to be serialized with [DataMember] , as explained in Using Data Contracts :

You can also explicitly create a data contract by using DataContractAttribute and DataMemberAttribute attributes. This is normally done by applying the DataContractAttribute attribute to the type. This attribute can be applied to classes, structures, and enumerations. The DataMemberAttribute attribute must then be applied to each member of the data contract type to indicate that it is a data member, that is, it should be serialized.

You have not applied [DataMember] to any of the members of your newses type, so none if its members are deserialized.

A second problem is that you have declared water_level_trend as an int , but it appears as an empty string in the JSON:

     "water_level_trend":"",

An empty string cannot be bound to an integer; if you try, DataContractJsonSerializer will throw the following exception:

There was an error deserializing the object of type ApiRegionalne. The value '' cannot be parsed as the type 'Int32'.

Since you appear to want to explicitly mark your types with data contract attributes, you can use the site https://jsonutils.com/ to auto-generate your types for you with the desired attributes applied. You can also choose to automatically camel-case your property and type names, bringing then into conformance with the recommended .Net style:

[DataContract]
public class Pagination
{
    [DataMember(Name = "totalitems")]
    public int Totalitems { get; set; }

    [DataMember(Name = "itemsperpage")]
    public int Itemsperpage { get; set; }
}

[DataContract]
public class Six // Fixed name from 6
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "city")]
    public string City { get; set; }

    [DataMember(Name = "slug_name")]
    public string SlugName { get; set; }
}

[DataContract]
public class Provinces
{
    [DataMember(Name = "6")]
    public Six Six { get; set; }
}

[DataContract]
public class News
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "shortcut")]
    public string Shortcut { get; set; }

    [DataMember(Name = "content")]
    public string Content { get; set; } // Fixed type from object

    [DataMember(Name = "rso_alarm")]
    public string RsoAlarm { get; set; }

    [DataMember(Name = "rso_icon")]
    public string RsoIcon { get; set; } // Fixed type from object

    [DataMember(Name = "valid_from")]
    public string ValidFrom { get; set; }

    [DataMember(Name = "0")]
    public string Zero { get; set; }  // Fixed name from 0

    [DataMember(Name = "valid_to")]
    public string ValidTo { get; set; }

    [DataMember(Name = "1")]
    public string One { get; set; } // Fixed name from 1

#if false
    // Removed since the correct type is unknown.
    [DataMember(Name = "repetition")]
    public object Repetition { get; set; }
#endif

    [DataMember(Name = "longitude")]
    public string Longitude { get; set; }

    [DataMember(Name = "latitude")]
    public string Latitude { get; set; }

    [DataMember(Name = "water_level_value")]
    public int WaterLevelValue { get; set; } // Fixed type to int

    [DataMember(Name = "water_level_warning_status_value")]
    public int WaterLevelWarningStatusValue { get; set; } // Fixed type to int

    [DataMember(Name = "water_level_alarm_status_value")]
    public int WaterLevelAlarmStatusValue { get; set; } // Fixed type to int

    [DataMember(Name = "water_level_trend")]
    public string WaterLevelTrend { get; set; } // This must remain a string since it appears as a non-numeric empty string in the JSON: "".

    [DataMember(Name = "river_name")]
    public string RiverName { get; set; }

    [DataMember(Name = "location_name")]
    public string LocationName { get; set; }

    [DataMember(Name = "created_at")]
    public string CreatedAt { get; set; }

    [DataMember(Name = "2")]
    public string Two { get; set; } // // Fixed name from 2

    [DataMember(Name = "updated_at")]
    public string UpdatedAt { get; set; }

    [DataMember(Name = "3")]
    public string Three { get; set; } // Fixed name from 3

    [DataMember(Name = "type")]
    public string Type { get; set; }

    [DataMember(Name = "provinces")]
    public Provinces Provinces { get; set; }
}

[DataContract]
public class ApiRegionalne
{
    [DataMember(Name = "pagination")]
    public Pagination Pagination { get; set; }

    [DataMember(Name = "newses")]
    public IList<News> Newses { get; set; }
}

Note it was necessary to make some manual fixes to the auto-generated types such as renaming numeric properties to some appropriate non-numeric name, eg 1 to One . In addition it was necessary to change the types of some properties that were null in the JSON from object to something more appropriate such as string . The manual changes are commented above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM