Having issues serializing json string to c# object - c#

I have a class that calls a webservice which returns a JSON string which I need to deserialize into a C# object. I was successfully able to do this; however, I came across a scenario that I am not sure exactly the best way to handle. More specifically, the JSON will either return a List<List<object>> or just a List<object>. I am having a problem when I deserialize if my object is List<object> and the JSON is List<List<object>>. In that case, an exception is thrown.
This is class that I am trying to deserialize:
public class WorkOrderJson
{
public string type { get; set; }
public Properties properties { get; set; }
public Geometry geometry { get; set; }
}
public class Properties
{
public string FeatureType { get; set; }
public string WorkOrderID { get; set; }
public string EqEquipNo { get; set; }
}
For the Geometry class the coordinates returned are the issue from above. If the JSON returned is a List<List<object>> it serializes fine.
public class Geometry
{
public string type { get; set; }
public List<List<double>> coordinates { get; set; }
}
This is how I am performing deserialization:
WorkOrderJson workOrderJson = new JavaScriptSerializer().Deserialize<List<WorkOrderJson>>(responseString);
where responseString is the JSON string returned from web service. Hope this makes sense. If anybody has come across a similar issue, any help would be much appreciated.
Here is an example for List<List<object>> where coordinates is the list:
[
{
"type": "Feature",
"properties": {
"FeatureType": "WORKORDER",
"WorkOrderID": "AMO172-2015-107",
"EqEquipNo": "AC-LIN-001"
},
"geometry": {
"type": "LineString",
"coordinates": [
[
-111.00041804208979,
33.0002148138019
],
[
-111.00027869450028,
33.000143209356054
]
]
},
"symbology": {
"color": "#990000",
"lineWidth": "8"
}
}
]
Here is an example for List<object>:
[
{
"type": "Feature",
"properties": {
"FeatureType": "WORKORDER",
"WorkOrderID": "AMO172-2015-115",
"EqEquipNo": "AC-LIN-001"
},
"geometry": {
"type": "Point",
"coordinates": [
-111.00041804208979,
33.0002148138019
]
}
}
]

So for anyone that cares changing the Geometry Class to the following solved my problem:
public class Geometry
{
public string type { get; set; }
public object coordinates { get; set; }
}
Just changed list to object. Then at runtime i can check whether the object is list of lists or just a list and proceed.

Create a custom JavaScriptConverter and register it with your JavaScriptSerializer.
You would then deserialize like this:
var converter = new JavaScriptSerializer();
converter.RegisterConverters(new List<JavaScriptConverter>() {new GeometryConverter()});
var workOrderJson = converter.Deserialize<List<WorkOrderJson>>(response);
This converter would work:
public class GeometryConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>(new Type[] {typeof(Geometry)}); }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Geometry geometry = obj as Geometry;
if (geometry != null)
{
// Create the representation
var result = new Dictionary<string, object>();
if (geometry.coordinates.Count == 1)
{
result.Add("type", "Point");
result.Add("coordinates", geometry.coordinates[0]);
}
else if (geometry.coordinates.Count > 1)
{
result.Add("type", "LineString");
result.Add("coordinates", geometry.coordinates);
}
return result;
}
return new Dictionary<string, object>();
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
Geometry geometry = null;
if (type == typeof(Geometry))
{
geometry = new Geometry();
geometry.type = (string)dictionary["type"];
geometry.coordinates = new List<List<double>>();
if ( geometry.type == "Point")
{
ArrayList arrayList = (ArrayList)dictionary["coordinates"];
geometry.coordinates.Add(ConvertCoordinates(arrayList));
}
else if (geometry.type == "LineString")
{
geometry.type = "LineString";
ArrayList coordinatesList = (ArrayList)dictionary["coordinates"];
foreach (ArrayList arrayList in coordinatesList)
{
geometry.coordinates.Add(ConvertCoordinates(arrayList));
}
}
}
return geometry;
}
private List<double> ConvertCoordinates(ArrayList coordinates)
{
var list = new List<double>();
foreach (var coordinate in coordinates)
{
list.Add((double)System.Convert.ToDouble(coordinate));
}
return list;
}
}

If I understand and you are trying to deserialize a List<List<a>> as a List<a>, it should error. You're telling it to deserialize it into something other than what it was before serialization. I would recommend either propagating some indication of which it is along with the string so you can check and deserialize as that type, or wrap the deserialization attempts and try one first, then the other if it fails.
Edit per update
public class WorkOrderJson<T>
{
public Geometry<T> geometry { get; set; }
public WorkOrderJson<List<T>> Promote()
{
var temp = new WorkOrderJson<List<T>>();
temp.geometry = geometry.Promote();
return temp;
}
}
public class Geometry<T>
{
public T coordinates { get; set; }
public Geometry<List<T>> Promote()
{
var temp = new Geometry<List<T>>();
temp.coordinates = new List<T>(){ coordinates };
return temp;
}
}
public List<WorkOrder<List<List<double>>>> Deserialize(string x)
{
try
{
return new JavaScriptSerializer().Deserialize<List<WorkOrderJson<List<List<double>>>>>(x);
}
catch(InvalidOperationException ex)
{
return new JavaScriptSerializer().Deserialize<List<WorkOrderJson<List<double>>>>(x).Select(workOrder => workOrder.Promote());
}
}

Related

C# serializa json to Dictionary [duplicate]

Given the following json:
[ {"id":"123", ... "data":[{"key1":"val1"}, {"key2":"val2"}], ...}, ... ]
that is part of a bigger tree, how can I deserialize the "data" property into:
List<MyCustomClass> Data { get; set; }
or
List<KeyValuePair> Data { get; set; }
or
Dictionary<string, string> Data { get; set; }
using Json.NET? Either version will do (I prefer List of MyCustomClass though). I already have a class that contains other properties, like this:
public class SomeData
{
[JsonProperty("_id")]
public string Id { get; set; }
...
public List<MyCustomClass> Data { get; set; }
}
where "MyCustomClass" would include just two properties (Key and Value). I noticed there is a KeyValuePairConverter class that sounds like it would do what I need, but I wasn't able to find an example on how to use it. Thanks.
The simplest way is deserialize array of key-value pairs to IDictionary<string, string>:
public class SomeData
{
public string Id { get; set; }
public IEnumerable<IDictionary<string, string>> Data { get; set; }
}
private static void Main(string[] args)
{
var json = "{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }";
var obj = JsonConvert.DeserializeObject<SomeData>(json);
}
But if you need deserialize that to your own class, it can be looks like that:
public class SomeData2
{
public string Id { get; set; }
public List<SomeDataPair> Data { get; set; }
}
public class SomeDataPair
{
public string Key { get; set; }
public string Value { get; set; }
}
private static void Main(string[] args)
{
var json = "{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }";
var rawObj = JObject.Parse(json);
var obj2 = new SomeData2
{
Id = (string)rawObj["id"],
Data = new List<SomeDataPair>()
};
foreach (var item in rawObj["data"])
{
foreach (var prop in item)
{
var property = prop as JProperty;
if (property != null)
{
obj2.Data.Add(new SomeDataPair() { Key = property.Name, Value = property.Value.ToString() });
}
}
}
}
See that I khow that Value is string and i call ToString() method, there can be another complex class.
Thanks #Boo for your answer but in my case I needed to take some small adjustements.
This is how my JSON looks like:
{
"rates": {
"CAD": 1.5649,
"CZK": 26.118,
...
},
"base": "EUR",
"date": "2020-08-16"
}
And my DTO looks like the following:
public IDictionary<string, decimal> Rates { get; set; }
public string Base { get; set; }
public DateTime Date { get; set; }
So the only adjustement was to remove the IEnumerable around the IDictionary.
I ended up doing this:
[JsonConverter(typeof(MyCustomClassConverter))]
public class MyCustomClass
{
internal class MyCustomClassConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
foreach (var prop in jObject)
{
return new MyCustomClass { Key = prop.Key, Value = prop.Value.ToString() };
}
return null;
}
public override bool CanConvert(Type objectType)
{
return typeof(MyCustomClass).IsAssignableFrom(objectType);
}
}
public string Key { get; set; }
public string Value { get; set; }
}
public class Datum
{
public string key1 { get; set; }
public string key2 { get; set; }
}
public class RootObject
{
public string id { get; set; }
public List<Datum> data { get; set; }
}
i used this wizard as well json2csharp.com to generate class for deserialized
for using that
using RestSharp;
using Newtonsoft.Json;
IRestResponse restSharp= callRestGetMethodby_restSharp(api_server_url);
string jsonString= restSharp.Content;
RootObject rootObj= JsonConvert.DeserializeObject<RootObject>(jsonString);
return Json(rootObj);
if you call rest by restsharp
public IRestResponse callRestGetMethodby_restSharp(string API_URL)
{
var client = new RestSharp.RestClient(API_URL);
var request = new RestRequest(Method.GET);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("cache-control", "no-cache");
IRestResponse response = client.Execute(request);
return response;
}
also you can get this 6 line of restsharp from getpostman.com tools
You can use public IEnumerable<IDictionary<string, string>> Data as the most answers are recommending, but it is not the best idea, since it creates a new dictionary for each array key value item. I recommend to use List<KeyValuePair<string, string>> instead ( or you can create a custom class as well instead of using KeyValuePair )
var json = "[{ \"id\": \"123\", \"data\": [ { \"key1\": \"val1\" }, { \"key2\" : \"val2\" } ] }]";
List<SomeData> listSomeData = JsonConvert.DeserializeObject<List<SomeData>>(json);
public class SomeData
{
[JsonProperty("id")]
public string Id { get; set; }
public List<KeyValuePair<string, string>> Data { get; set; }
[JsonConstructor]
public SomeData(JArray data)
{
Data = data.Select(d => new KeyValuePair<string, string>(
((JObject)d).Properties().First().Name,
((JObject)d).Properties().First().Value.ToString()))
.ToList();
}
}

JSON complex type that can be an object or an array of objects [duplicate]

This question already has answers here:
How to handle both a single item and an array for the same property using JSON.net
(9 answers)
Closed 3 years ago.
I am trying to process an object that can be either an array of object or just the object. Using the code below only works when the naics is an object and not an array. What am I doing wrong?
Here is the shortest example I can come up with:
[{
"section": "52.219-1.b",
"naics": [{
"naicsName": "Engineering Services",
"isPrimary": true,
"ExcpCounter": 1,
"isSmallBusiness": "Y",
"naicsCode": 541330
},
{
"naicsName": "Military and Aerospace Equipment and Military Weapons",
"isPrimary": true,
"ExcpCounter": 2,
"isSmallBusiness": "Y",
"naicsCode": 541330
}
]
},
{
"section": "52.219-1.b",
"naics": {
"naicsName": "Janitorial Services",
"isPrimary": true,
"isSmallBusiness": "Y",
"naicsCode": 561720
}
}
]
I will only have one of the types but I forced two in an array to force it into Quick Type.
My classes are:
[JsonProperty("naics", NullValueHandling = NullValueHandling.Ignore)]
public AnswerNaics Naics { get; set; }
public partial struct AnswerNaics
{
public AnswerNaic Naic;
public AnswerNaic[] NaicArray;
public static implicit operator AnswerNaics(AnswerNaic Naic) => new AnswerNaics { Naic = Naic };
public static implicit operator AnswerNaics(AnswerNaic[] NaicArray) => new AnswerNaics { NaicArray = NaicArray };
}
public partial class AnswerNaic
{
[JsonProperty("naicsName")]
public string NaicsName { get; set; }
[JsonProperty("hasSizeChanged")]
public string HasSizeChanged { get; set; }
[JsonProperty("isPrimary")]
public bool IsPrimary { get; set; }
[JsonProperty("ExcpCounter", NullValueHandling = NullValueHandling.Ignore)]
public long? ExcpCounter { get; set; }
[JsonProperty("isSmallBusiness")]
public string IsSmallBusiness { get; set; }
[JsonProperty("naicsCode")]
public string NaicsCode { get; set; }
}
internal class NaicsConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(AnswerNaics) || t == typeof(AnswerNaics?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<AnswerNaic>(reader);
return new AnswerNaics { Naic = objectValue };
case JsonToken.StartArray:
var arrayValue = serializer.Deserialize<AnswerNaic[]>(reader);
return new AnswerNaics { NaicArray = arrayValue };
}
throw new Exception("Cannot unmarshal type AnswerNaics");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (AnswerNaics)untypedValue;
if (value.NaicArray != null)
{
serializer.Serialize(writer, value.NaicArray);
return;
}
if (value.Naic != null)
{
serializer.Serialize(writer, value.Naic);
return;
}
throw new Exception("Cannot marshal type Naics");
}
public static readonly NaicsConverter Singleton = new NaicsConverter();
}
I have more object or array nodes, but I am just trying to figure out one to be able to apply to all of them.
Since you cannot change the incoming JSON, you're going to need a custom converter instead. Something like this for example:
public class NaicsConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(Naics);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
var naics = new Naics();
switch (reader.TokenType)
{
case JsonToken.StartObject:
// We know this is an object, so serialise a single Naics
naics.Add(serializer.Deserialize<Naic>(reader));
break;
case JsonToken.StartArray:
// We know this is an object, so serialise multiple Naics
foreach(var naic in serializer.Deserialize<List<Naic>>(reader))
{
naics.Add(naic);
}
break;
}
return naics;
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And the supporting classes:
public class Root
{
public string Section { get; set; }
[JsonConverter(typeof(NaicsConverter))]
public Naics Naics { get; set; }
}
// This isn't ideal, but it's quick and dirty and should get you started
public class Naics : List<Naic>
{
}
public class Naic
{
public string NaicsName { get; set; }
public bool IsPrimary { get; set; }
public string IsSmallBusiness { get; set; }
public long NaicsCode { get; set; }
}
And finally, to deserialise:
var settings = new JsonSerializerSettings {Converters = {new NaicsConverter()}};
var root = JsonConvert.DeserializeObject<Root[]>(Json, settings);
Now your object will get serialised into the list, but as a single item.
You can solve this using a dynamic field in your class.
Consider this JSON:
[
{
"field1": "val1",
"nested": [
{
"nestedField": "val2"
},
{
"nestedField": "val3"
}
]
},
{
"field1": "val4",
"nested":
{
"nestedField": "val5"
}
}
]
nested field is first an array with 2 objects and in the second appearance a single object. (similar to the JSON you posted)
So the class representation would look like:
public class RootObject
{
public string field1 { get; set; }
public dynamic nested { get; set; }
public List<NestedObject> NestedObjects
{
get
{
if(nested is JArray)
{
return JsonConvert.DeserializeObject<List<NestedObject>>(nested.ToString());
}
var obj = JsonConvert.DeserializeObject<NestedObject>(nested.ToString());
return new List<NestedObject> { obj };
}
}
}
public class NestedObject
{
public string nestedField { get; set; }
}
The Deserialization code is trivial using Newtonsoft JSON:
var objectList = JsonConvert.DeserializeObject<List<RootObject>>("some_json");
foreach(var v in objectList)
{
foreach(var n in v.NestedObjects)
{
Console.WriteLine(n.nestedField);
}
}
The only change is an implementation of NestedObjects ready only property. It check if the dynamic object is JArray or object. In any case, it returns a List of nested objects.

Custom BSON Key Value Serializer

I ran into some trouble trying to convert a class to a BSON document.
I have Custom1 and Custom2 which should behave a little different. How do I create a custom serializer which "unfold" the KeyValuePair so it generates the expected result (See below)? You can see the code example below together with the expected result.
Moreover, I'm using Mongo BSON library for serializing the object.
public class UserData
{
public UserData()
{
Id = 100;
Name = "Superuser";
Custom1 = new KeyValuePair<string, double>("HelloWorld1", 1);
Custom2 = new KeyValuePair<string, double>("HelloWorld2", 2);
}
public int Id { get; set; }
public string Name { get; set; }
public KeyValuePair<string, double> Custom1 { get; set; }
public KeyValuePair<string, double> Custom2 { get; set; }
}
Execute test code:
var userdata = new UserData();
var doc = userdata.ToBsonDocument();
Current result:
{
"Id": 100,
"Name": "Superuser",
"Custom1": {
"Key": "HelloWorld1",
"Value": 1
},
"Custom2": {
"Key": "HelloWorld2",
"Value": 2
}
}
Expected result:
{
"Id": 100,
"Name": "Superuser",
"HelloWorld1": 1,
"HelloWorld2": 2
}
For such a complex serialization case you have to implement custom IBsonSerializer converter for your class.
Here is the working example:
public class UserDataSerializer : SerializerBase<UserData>
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, UserData value)
{
context.Writer.WriteStartDocument();
context.Writer.WriteName("Id");
context.Writer.WriteInt32(value.Id);
context.Writer.WriteName("Name");
context.Writer.WriteString(value.Name);
WriteKeyValue(context.Writer, value.Custom1);
WriteKeyValue(context.Writer, value.Custom2);
context.Writer.WriteEndDocument();
}
private void WriteKeyValue(IBsonWriter writer, KeyValuePair<string, double> kv)
{
writer.WriteName(kv.Key);
writer.WriteDouble(kv.Value);
}
public override UserData Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
//TODO: implement data deserialization using context.Reader
throw new NotImplementedException();
}
}
To make it work you also need to register our UserDataSerializer somehow. IBsonSerializationProvider is the easiest way to achieve that.
public class UserDataSerializationProvider : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
if (type == typeof(UserData)) return new UserDataSerializer();
return null;
}
}
And finally we can use it.
//register our serialization provider
BsonSerializer.RegisterSerializationProvider(new UserDataSerializationProvider());
var userdata = new UserData();
var doc = userdata.ToBsonDocument();
Here is the result:
{ "Id" : 100, "Name" : "Superuser", "HelloWorld1" : 1.0, "HelloWorld2" : 2.0 }
You may also want to implement UserDataSerializer.Deserialize() method in order to provide the backward conversion. It can be done in the same way using context.Reader.
More information about custom serialization process can be found here.
If you are using the driver 2.0 or higher, you could try to make your class into a DynamicObject, like this:
public class UserData : DynamicObject
{
public UserData()
{
Id = 100;
Name = "Superuser";
Custom1 = new KeyValuePair<string, double>("HelloWorld1", 1);
Custom2 = new KeyValuePair<string, double>("HelloWorld2", 2);
}
public id Id { get; set; }
public string Name { get; set; }
public KeyValuePair<string, double> Custom1 { get; set; }
public KeyValuePair<string, double> Custom2 { get; set; }
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
string name = binder.Name;
result = null;
if(name.Equals(Custom1.Key))
result = Custom1.Value;
else if(name.Equals(Custom2.Key))
result = Custom2.Value;
return result != null;
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
string name = binder.Name;
if(name.Equals(Custom1.Key))
Custom1.Value = value;
else if(name.Equals(Custom2.Key))
Custom2.Value = value;
return name.Equals(Custom1.Key) ||
name.Equals(Custom2.Key);
}
}
According to the release documentation, you should then be able to do this:
var userdata = new UserData();
var doc = ((dynamic) userdata).ToBsonDocument();
And get the expected format.

JSON value is sometimes a string and sometimes an object

I have some JSON that can come in two different formats. Sometimes the location value is a string, and sometimes it is an object. This is a sample of the first format:
{
"result": [
{
"upon_approval": "Proceed to Next Task",
"location": "",
"expected_start": ""
}
]
}
Class definitions for this:
public class Result
{
public string upon_approval { get; set; }
public string location { get; set; }
public string expected_start { get; set; }
}
public class RootObject
{
public List<Result> result { get; set; }
}
Here is the JSON in the second format:
{
"result": [
{
"upon_approval": "Proceed to Next Task",
"location": {
"display_value": "Corp-HQR",
"link": "https://satellite.service-now.com/api/now/table/cmn_location/4a2cf91b13f2de00322dd4a76144b090"
},
"expected_start": ""
}
]
}
Class definitions for this:
public class Location
{
public string display_value { get; set; }
public string link { get; set; }
}
public class Result
{
public string upon_approval { get; set; }
public Location location { get; set; }
public string expected_start { get; set; }
}
public class RootObject
{
public List<Result> result { get; set; }
}
When deserializing, I get errors when the JSON format does not match my classes, but I don't know ahead of time which classes to use because the JSON format changes. So how can I dynamically get these two JSON formats to deserialize into one set of classes?
This is how I am deserializing now:
JavaScriptSerializer ser = new JavaScriptSerializer();
ser.MaxJsonLength = 2147483647;
RootObject ro = ser.Deserialize<RootObject>(responseValue);
To solve this problem you'll need to make a custom JavaScriptConverter class and register it with the serializer. The serializer will load the result data into a Dictionary<string, object>, then hand off to the converter, where you can inspect the contents and convert it into a usable object. In short, this will allow you to use your second set of classes for both JSON formats.
Here is the code for the converter:
class ResultConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type> { typeof(Result) }; }
}
public override object Deserialize(IDictionary<string, object> dict, Type type, JavaScriptSerializer serializer)
{
Result result = new Result();
result.upon_approval = GetValue<string>(dict, "upon_approval");
var locDict = GetValue<IDictionary<string, object>>(dict, "location");
if (locDict != null)
{
Location loc = new Location();
loc.display_value = GetValue<string>(locDict, "display_value");
loc.link = GetValue<string>(locDict, "link");
result.location = loc;
}
result.expected_start = GetValue<string>(dict, "expected_start");
return result;
}
private T GetValue<T>(IDictionary<string, object> dict, string key)
{
object value = null;
dict.TryGetValue(key, out value);
return value != null && typeof(T).IsAssignableFrom(value.GetType()) ? (T)value : default(T);
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
Then use it like this:
var ser = new JavaScriptSerializer();
ser.MaxJsonLength = 2147483647;
ser.RegisterConverters(new List<JavaScriptConverter> { new ResultConverter() });
RootObject ro = serializer.Deserialize<RootObject>(responseValue);
Here is a short demo:
class Program
{
static void Main(string[] args)
{
string json = #"
{
""result"": [
{
""upon_approval"": ""Proceed to Next Task"",
""location"": {
""display_value"": ""Corp-HQR"",
""link"": ""https://satellite.service-now.com/api/now/table/cmn_location/4a2cf91b13f2de00322dd4a76144b090""
},
""expected_start"": """"
}
]
}";
DeserializeAndDump(json);
Console.WriteLine(new string('-', 40));
json = #"
{
""result"": [
{
""upon_approval"": ""Proceed to Next Task"",
""location"": """",
""expected_start"": """"
}
]
}";
DeserializeAndDump(json);
}
private static void DeserializeAndDump(string json)
{
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new List<JavaScriptConverter> { new ResultConverter() });
RootObject obj = serializer.Deserialize<RootObject>(json);
foreach (var result in obj.result)
{
Console.WriteLine("upon_approval: " + result.upon_approval);
if (result.location != null)
{
Console.WriteLine("location display_value: " + result.location.display_value);
Console.WriteLine("location link: " + result.location.link);
}
else
Console.WriteLine("(no location)");
}
}
}
public class RootObject
{
public List<Result> result { get; set; }
}
public class Result
{
public string upon_approval { get; set; }
public Location location { get; set; }
public string expected_start { get; set; }
}
public class Location
{
public string display_value { get; set; }
public string link { get; set; }
}
Output:
upon_approval: Proceed to Next Task
location display_value: Corp-HQR
location link: https://satellite.service-now.com/api/now/table/cmn_location/4a2cf91b13f2de00322dd4a76144b090
----------------------------------------
upon_approval: Proceed to Next Task
(no location)

Json Deserialization C#

I'm trying to deserialize a Json string usign Json.NET. I have a basic understanding about it but I've been trying for days and can't make it work, here's my code. (Please ignore any unecessary/extra code, have in mind I was trying multiple solutions based on what I found after researching).
public class Location
{
private string ab_;
private int c_;
public string name { get { return ab_; } set { value = ab_; } }
public int woeid { get { return c_; } set { value = c_; } }
}
public class Trend
{
private string x_, y_, z_;
private object a_, b_;
public string query { get { return x_; } set { value = x_; } }
public string name { get { return y_; } set { value = y_; } }
public object promoted_content { get { return a_; } set { value = a_; } }
public string url { get { return z_; } set { value = z_; } }
public object events { get { return b_; } set { value = b_; } }
}
public class RootObject
{
private string o, l;
private List<Location> list1;
private List<Trend> list2;
public List<Location> locations { get { return list1; } set { value = list1; } }
public string created_at { get { return o; } set { value = o; } }
public List<Trend> trends { get { return list2; } set { value = list2; } }
public string as_of { get { return l; } set { value = l; } }
}
RootObject values = JsonConvert.DeserializeObject<RootObject>(jsonString)
Now the Json string that im trying to deserialize is this one:
[
{
"as_of":"2012-08-31T15:31:55Z",
"trends":[
{
"query":"%23GDTHATXX",
"name":"#GDTHATXX",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%23GDTHATXX",
"events":null
},
{
"query":"%23UnMundoEnElQue",
"name":"#UnMundoEnElQue",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%23UnMundoEnElQue",
"events":null
},
{
"query":"%23%C3%A7ekicibuluyorum",
"name":"#\u00e7ekicibuluyorum",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%23%C3%A7ekicibuluyorum",
"events":null
},
{
"query":"%22Darren%20Kenny%22",
"name":"Darren Kenny",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%22Darren%20Kenny%22",
"events":null
},
{
"query":"%22Richard%20Wright%22",
"name":"Richard Wright",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%22Richard%20Wright%22",
"events":null
},
{
"query":"Yossi",
"name":"Yossi",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=Yossi",
"events":null
},
{
"query":"Filipinas",
"name":"Filipinas",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=Filipinas",
"events":null
},
{
"query":"%22Javi%20Garc%C3%ADa%22",
"name":"Javi Garc\u00eda",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%22Javi%20Garc%C3%ADa%22",
"events":null
},
{
"query":"%22Van%20der%20Vaart%22",
"name":"Van der Vaart",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=%22Van%20der%20Vaart%22",
"events":null
},
{
"query":"SSN",
"name":"SSN",
"promoted_content":null,
"url":"http:\/\/twitter.com\/search\/?q=SSN",
"events":null
}
],
"created_at":"2012-08-31T15:30:32Z",
"locations":[
{
"name":"Globales",
"woeid":1
}
]
}
]
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Twitter.TrendParser+RootObject' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '', line 1, position 1.
As i said before i have a basic understanding of the Json format, and i've been trying using different types of classes to deserialize with the same result, any tip or any idea about what the problem may be?. I am also stuck with .NET 2.0 and not 3rd party libraries aside from json.NET.
Thank you for the attention.
EDIT *
Apparently even if i try declaring List value, the variable "value" won't be created in the actual context, any way to fix that.
Your JSON is an array containing one object.
This means that JSON.NET will be expecting single object but getting a list. The error message is basically telling you that.
Give this a try:
List<RootObject> values = JsonConvert.DeserializeObject<List<RootObject>>(receiving);
enter code here/// the classes
public class MambuData
{
public mambuData[] mambuDataS { get; set; }
}
public class mambuData
{
public string encodedKey { get; set; }
public string id { get; set; }
public DateTime creationDate { get; set; }
public DateTime lastModifiedDate { get; set; }
public string name { get; set; }
public string phoneNumber { get; set; }
public string emailAddress { get; set; }
}
///the method
private string ParseMambuData(string streamResult)
{
string R = "";
List<mambuData> mambuDataList = JsonConvert.DeserializeObject<List<mambuData>>(streamResult);
foreach (mambuData m in mambuDataList)
{
//put data in db if you want
}
return R;
}

Categories

Resources