I have the following Json string that I need to deserialize.
{"123456789":
{"short_description":"Delivered",
"detail_description":"Your item has been delivered"
}
}
The first field "123456789" is an id number, so basically this value can be different depending on the data being queried.
I'm using C# in visual studio. Obviously because the value of the first field can change I can't use a predefined class to deserialize the JSON into because this field will be used as the class name but the field value won't match the class name.
Is there a way to deserialize this into some sort of dynamic class but still access the fields as if it was a predefined class?
Alternatively is there a way to deserialize this into a predefined class even thought the class name doesn't match?
The service providing this data is a third party one so i don't have any control over it.
Here is one way which I use in production code. It might not be perfect, but it gets the job done.
using using System.Web.Script.Serialization;
// .....
public object GetJson(string url)
{
var json = Get(url); // I have code that makes this work, it gets a JSON string
try
{
var deserializer = new JavaScriptSerializer();
var result = deserializer.DeserializeObject(json);
return result;
}
catch (ArgumentException e)
{
// Error handling....
}
}
The object you receive back will be a generic Map, List, or whatever depending on the structure of the JSON. If you know what structure to expect, this is very useful without writing a customized parser or target object type.
You could then enumerate the keys of the Map, for example, to find your key that varies. A wrapper or conversion would then provide a consistent API to the rest of your application layer. Something like:
public class Order {
public string OrderNum { private set; get; }
public string ShortDesc { private set; get; }
public string Desc { private set; get; }
public static Order FromJson(object jsonResult)
{
var m = jsonResult as Map<string, object>;
// Handle errors, but I am not
var firstPair = m.First();
var detail = firstPair.Value as Map<string, object>;
var dummy = new Order()
{
OrderNum = firstPair.Key,
ShortDesc = detail["short_description"].ToString();
Desc = detail["detail_description"].ToString();
}
return dummy;
}
}
I liked answer above so I refactored it a bit. You'll need references to System.Web.Extensions.dll and System.Web.Script.Serialization.
Here's the class:
public class Order
{
public string OrderNum { private set; get; }
public string ShortDesc { private set; get; }
public string Desc { private set; get; }
public static Order FromJson(string jsonResult)
{
JavaScriptSerializer js = new JavaScriptSerializer();
// Should deserialize right to Dictionary<string, object>
// var result = ((Dictionary<string, object>)js.Deserialize<dynamic>(jsonResult)).First();
var result = js.Deserialize<Dictionary<string, object>>(jsonResult).First();
var detail = (Dictionary<string, object>)result.Value;
return new Order()
{
OrderNum = result.Key,
ShortDesc = detail["short_description"].ToString(),
Desc = detail["detail_description"].ToString()
};
}
}
And how to call it:
string json = "{\"123456789\": {\"short_description\":\"Delivered\", \"detail_description\":\"Your item has been delivered\" } }";
Order o = Order.FromJson(json);
You'll need to implement error handling on your own however.
Related
Deserializing the following json
{
"MetaData1": "hello world",
"MetaData2": 2022,
"Data": {
"ObjectA": {
"id": 1,
"name": "steve",
"hobbies": 1
},
"ObjectB": {
"id": 2,
"name": "dave",
"age": 55
}
}
}
into corresponding c# objects
public class ObjectBase
{
public int id { get; set; }
public string name { get; set; }
}
public class ObjectA : ObjectBase
{
public int hobbies { get; set; }
}
public class ObjectB : ObjectBase
{
public int age { get; set; }
}
public class Data
{
public ObjectA ObjectA { get; set; }
public ObjectB ObjectB { get; set; }
}
public class Root
{
public string metaData1 { get; set; }
public int metaData2 { get; set; }
public Data Data { get; set; }
}
using
Root object = JsonConvert.DeserializeObject<Root>(json);
How could I search the id properties of the object properties of Root.Data for a matching int and return the corresponding name property.
It would also be useful to be able to create List<ObjectBase> so that other LINQ operations could be performed on these objects.
i think what i am ultimately after here is to end up with List<ObjectBase>.
This can be achieved easily with System.Text.Json (or Newtonsoft).
The most natural representation (IMO) given your Json structure would be to deserialize into a Dictionary<string, ObjectBase>. Then you could convert the dictionary to a List<ObjectBase>. You need a class to match the Data element in your (updated) Json:
// 'root' class to represent the 'Data' element
public class Root
{
public string MetaData1 { get; set; }
public int MetaData2 { get; set; }
public Dictionary<string, ObjectBase> Data { get; set; }
}
// Dictionary<string, ObjectBase>
var model = JsonSerializer.Deserialize<Root>(json);
foreach (var key in model.Data.Keys)
// do something with model.Data[key].id/name
// convert to List<ObjectBase>
var list = new List<ObjectBase>(model.Data.Values);
Expanding on Lasse V. Karlsen's comment, you could instead add all properties to a single class and deserialize into a Dictionary<string, SingleClass>:
public class SingleClass
{
public int id { get; set; }
public string name { get; set; }
public int hobbies { get; set; }
public int age { get; set; }
// all other properties...
}
If you choose this method you may want to consider making the additional properties nullable (if you're interested in differentiating between no hobbies property or someone with hobbies = 0, for example).
The methods above will deserialize into either ObjectBase or the SingleClass.
Demo online
Name only lookup
If you need to look up the name property based on the id then you can do that with the following code:
var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var name = (from node in semiParsed.Values
let id = (int)node.GetValue("id")
where id == lookupId
select (string)node.GetValue("name"))
.FirstOrDefault();
Console.WriteLine(name);
First we deserialize the json into a collection
The top most properties' name will be the keys of the Dictionary
The top most properties' object will be treated as JObjects (semi parsed jsons)
Then we perform a Linq to Json query
We iterate through the JObjects and retrieve their id property
GetValue returns a JToken and since we know it is a number, we cast it to int
We perform a filtering based on the lookupId
And we select the name property's value
Finally we need to issue a FirstOrDefault method call because the previous query returns an IEnumerable<string>
Here I have assumed that the the id is unique. If the provided lookupId is not defined inside the json then the result will be null.
Wrapping object lookup
If you need to perform a look up for the wrapping object then you need to use Json.NET Schema as well:
var generator = new JSchemaGenerator();
JSchema schemaA = generator.Generate(typeof(ObjectA));
JSchema schemaB = generator.Generate(typeof(ObjectB));
var semiParsed = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(json);
var theNode = (from node in semiParsed.Values
let id = (int)node.GetValue("id")
where id == lookupId
select node)
.FirstOrDefault();
if (theNode == null)
return;
if (theNode.IsValid(schemaA))
{
var objA = theNode.ToObject<ObjectA>();
Console.WriteLine(objA.hobbies);
} else if (theNode.IsValid(schemaB))
{
var objB = theNode.ToObject<ObjectB>();
Console.WriteLine(objB.age);
}
First we generate two json schemas from the class definitions
Then we perform almost the same query the only difference here is the select part
We return here the whole JObject object instead of just its name
Finally perform a schema validation
If the retrieved json matches to schemaA then we can safely convert (ToObject) to ObjectA
We check the json against schemaB as well
the simpliest way would be convert your json to dictionary of JObjects, in this case you don't need any classes at all
var dict = JObject.Parse(json).Properties().ToDictionary(jo => jo.Value["id"],jo=>jo.Value);
var searchId=2;
var name = dict[searchId]["name"]; // dave
or you can deserialize json to list of c# objects
List<ObjectBase> list = JObject.Parse(json).Properties()
.Select(jo => jo.Value.ToObject<ObjectBase>()).ToList();
and use linq to get data
This answer using reflection is poorly optimised as pointed out by serge in a reply to his answer.
foreach (var prop in root.GetType().GetProperties())
{
var obj = prop.GetValue(root);
if ((int) obj.GetType().GetProperty("id").GetValue(obj) == 2)
{
Console.WriteLine(obj.GetType().GetProperty("name").GetValue(obj).ToString());
break;
}
}
Another method that gets List<ObjectBase> using reflection
var objects = root.Data.Objects;
List<ObjectBase> objectList = objects.GetType().GetProperties().ToList<PropertyInfo>().ConvertAll(x => (ObjectBase)x.GetValue(objects));
I am going to leave this answer here incase it helps someone who can't get to this point by desterilisation (maybe their objects weren't crated by desterilisation).
I have one concrete class called ShipFromAddress and where I am deserializing my json this below way
JavaScriptSerializer jss = new JavaScriptSerializer();
oShipFromAddress = jss.Deserialize<ShipFromAddress>(Request.Cookies["ShipFromAddress"].Value);
Concrete class
public class ShipFromAddress
{
public string Weight
{
get;
set;
}
public string addressLine1
{
get;
set;
}
public string addressLine2
{
get;
set;
}
public string city
{
get;
set;
}
public string postcode
{
get;
set;
}
public string countrycode
{
get;
set;
}
public string StateCode
{
get;
set;
}
}
I do not want to create or use concrete class rather I want to do that deserialization on the fly with the help of dynamic object or anonymous class concept. Please guide me with sample code.
i got two solution.....which looks good
1) when need to pass multiple data serialize to anonymous the example would be
var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);
public void LogEmployees (IEnumerable<dynamic> list)
{
foreach (dynamic item in list)
{
string name = item.Name;
int id = item.Id;
}
}
method argument type must be IEnumerable<dynamic> because LogEmployees() function expecting multiple data
2) when passing single data the code look like
public class Program
{
private static void Thing(dynamic other)
{
Console.WriteLine(other.TheThing);
}
private static void Main()
{
var things = new { TheThing = "Worked!" };
Thing(things);
}
}
With JavaScriptSerializer you can use the DeserializeObject method from serializer which will return just an object:
JavaScriptSerializer jss = new JavaScriptSerializer();
object obj= jss.DeserializeObject(Request.Cookies["ShipFromAddress"].Value);
Internally it will be represented as a Dictionary<string, object>, so you can cast it to it and use like this:
var values = (Dictionary<string, object>)jss.DeserializeObject(Request.Cookies["ShipFromAddress"].Value);
var addressLine1 = values["addressLine1"].ToString();
Or you can cast it to dynamic:
dynamic values = jss.DeserializeObject(Request.Cookies["ShipFromAddress"].Value);
var addressLine1 = values["addressLine1"].ToString();
Alternatively, You can use Json.NET library and it's JsonConvert class (benchmarks show that it performs faster than JavaScriptSerializer). The code will look like this:
dynamic values = JsonConvert.DeserializeObject(Request.Cookies["ShipFromAddress"].Value);
var addressLine1 = values.addressLine1;
I use Newtonsoft.Json
string source = Request.Cookies["ShipFromAddress"].Value as string;
var address = JsonConvert.DeserializeObject<ShipFromAddress>(source);
I'm writing a .NET library (using Newtonsoft) that interacts with a REST service, and I have a service that's returning json, but the json id field is called '$id'. So I can't just create a corresponding $id property in my C# data class. I tried to use something like
[JsonObject(MemberSerialization.OptOut)]
public class DocData
{
[JsonProperty("$id")]
public string id { get; set; }
public string Name { get; set; }
}
but while Name gets assigned, the id property does not. Anyone know how to map this json key to .NET?
Thanks
It looks like this is a bug in JSON.NET, and I think you should report it. It works fine in LINQPad for any property name except $id.
void Main()
{
var s = JsonConvert.SerializeObject(new DocData{id = "hi", Name = "world"}).Dump();
JsonConvert.DeserializeObject<DocData>(s).Dump();
}
public class DocData
{
// [JsonProperty("i$d")] // this would work
// [JsonProperty("_id")] // as would this
// [JsonProperty("$name")] // and even this
[JsonProperty("$id")] // but this fails
public string id { get; set; }
public string Name { get; set; }
}
Evidently Json.NET uses $id as a reserved word to help it deal with object references.
var dd = new DocData{id = "hi", Name = "world"};
JsonConvert.SerializeObject(new[]{dd, dd}, new JsonSerializerSettings{PreserveReferencesHandling = PreserveReferencesHandling.Objects}).Dump();
// Output: [{"$id":"1","$id":"hi","Name":"world"},{"$ref":"1"}]
Still, it seems like it should let you capture the $id property if you're not using reference handling.
As a workaround, you can parse it into a JObject, and pull the property out directly:
var id = JObject.Parse(s)["$id"];
var obj = JsonConvert.DeserializeObject<DocData>(s);
obj.id = id;
I want to store the results from JSON in properties, but I don't know how. I'm using ASP.NET with MVC 4/Razor.
My model's constructor is:
public UserModel()
{
WebClient request = new WebClient();
string response = request.DownloadString(url);
JObject _naturalUserObject = (JObject)JsonConvert.DeserializeObject(response);
}
And I have the follow properties:
[Key]
public int Id { get; set; }
public int DisplayName { get; set; }
public int Avatar { get; set; }
To access a simple value from my JSON:
_naturalUserObject["users"][0]["name"];
The final question is: how can I store each value from my JObject in my model's properties and finally display it into my view?
Thanks in advance.
/EDIT/
My model now is:
public UserModel()
{
WebClient request = new WebClient();
string response = request.DownloadString(String.Format("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key={0}&steamids={1}", ConfigurationManager.AppSettings["SteamApiKey"].ToString(), HttpContext.Current.Request.Cookies["SteamIdCookie"].Value));
string _naturalUserObject = JsonConvert.DeserializeObject<string>(response);
}
And one of my property is:
private string _avatar;
public string Avatar
{
get { return _avatar; }
set { _avatar = _naturalUserObject["response"]["players"][0]["avatar"]; }
}
But without success. =(
Lets say you have the following Json
string yourJsonString = "{\"FIRST_NAME\":\"Foo\",\"LAST_NAME\":\"Bar\"}";
You could model this Json as:
public class JsonModel
{
[JsonProperty("FIRST_NAME")]
public string FirstName {get; set;}
[JsonProperty("LAST_NAME")]
public string LastName {get; set;}
}
Note that you can use JsonPropertyAttribute to tell Json.Net what the property's corresponding json field is.
Now, that you have your model set up, can use JsonConvert.DeserializeObject<T>(...) to get a strongly typed instance of your json model.
JsonModel jsonModel = JsonConvert.DeserializeObject<JsonModel>(yourJsonString);
string firstName = jsonModel.FirstName; // Foo
string lastName = jsonModel.LastName; // Bar
As someone had mentioned, if you do it this way, you won't have to deal with JObject and moreover, it will force you to actually understand the structure of the json being returned.
Specifically in your example, you could store an object of type JsonModel and in your model's constructor initialize it using JsonConvert.DeserializeObject<T>. Your public properties could then just call into that JsonModel instance and get the appropriate values.
Here's a more detailed example. Assume you are getting back the json I had provided above and are using the same model we created before. Let's say you have a private field in your class of type JsonModel
private JsonModel jsonModel;
You can initialize it in your constructor:
public UserModel()
{
WebClient request = new WebClient();
string response = request.DownloadString(url);
jsonModel = JsonConvert.DeserializeObject<JsonModel>(response);
}
Now, your public properties can simply call into this JsonModel object.
public string FirstName
{
get { return jsonModel.FirstName; }
set { jsonModel.FirstName = value; }
}
I recommend ServiceStack.Text (available as a standalone NuGet package install, without the rest of the framework if you don't need it).
This adds two nice extension methods:
public class MyPOCO
{
public string Name {get; set; }
public int Age {get; set; }
}
And later:
string json = myPocoInstance.ToJson();
and:
MyPOCO instance = jsonString.FromJson<MyPOCO>();
Very fast too!
If you use Json.net you can deserialize directly into a clr object (which could be your viewmodel or model), you won't have to deal with JObject.
JsonConvert.DeserializeObject<myviewmodelormodel>(myjsondata);
If you get the object back as a string in JSON format. You can use the JSON de-serializer like this:
Put this into a static class this will become an extension method to all strings
public static T Deserialize<T>(this string json)
{
var obj = Activator.CreateInstance<T>();
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T) serializer.ReadObject(ms);
}
return obj;
}
EX:
this calls a url getting the result set in a string, then calls the
extension method to return an object.
the url returns MyPOCO
var stringValue = HttpGet(url);//how you get the value from a web service call
var myUserModel = stringValue.Deserialize<MyPOCO>();
I am accessing an API which is returning JSon in the format:
{"status":1,"complete":1,"list":{"293352541":{"item_id":"293352541","fave":"0"},"247320106":{"item_id":"247320106","fave":"0"},"291842735":{"item_id":"291842735","fave":"0"} .....
The problem I am having is with the number before the item_id tag. It is breaking any attempt I make at deserialising as I cannot represent this random integer in an object that I deserialise in to.
I would expect this number to be, for example, the word "Item", so that it is key representing the enclosed object, but having this number means I cannot make an object representation of the JSon.
So
public class MyClass
{
public string status { get; set; }
public string complete { get; set; }
public List<MyObject> list { get; set; }
}
public class MyObject
{
public string item_id { get; set; }
public string fave { get; set; }
}
then
var items = new JavaScriptSerializer().Deserialize<MyClass>(jsontext);
dersialises, but items.list is empty.
Also,
dynamic result = JSon.Parse(jsontext);
works, but I cannot deserialise or access the list of items in a nice way.
Is there any way to do this? thanks
Because it doesn't require predefined types to deserialize into, you can do this with json.net (also available with nuget). For instance:
var jObj = JObject.Parse(data);
var sense = jObj["list"]
.Select(x => (JProperty)x)
.Select(p => new {
propName = p.Name,
itemId = p.Value["item_id"],
fave = p.Value["fave"]});