Deserialize json to dynamic/anonymous class asp.net - c#

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);

Related

Deserialize JSON to 2 different models

Does Newtonsoft.JSON library have a simple way I can automatically deserialize JSON into 2 different Models/classes?
For example I get the JSON:
[{
"guardian_id": "1453",
"guardian_name": "Foo Bar",
"patient_id": "938",
"patient_name": "Foo Bar",
}]
And I need de-serialize this to the following models:
class Guardian {
[JsonProperty(PropertyName = "guardian_id")]
public int ID { get; set; }
[JsonProperty(PropertyName = "guardian_name")]
public int Name { get; set; }
}
class Patient {
[JsonProperty(PropertyName = "patient_id")]
public int ID { get; set; }
[JsonProperty(PropertyName = "patient_name")]
public int Name { get; set; }
}
Is there a simple way to deserialize this JSON into 2 Models without having to iterate over the JSON? Maybe JSON property ids will just work?
Pair<Guardian, Patient> pair = JsonConvert.DeserializeObject(response.Content);
First off, your models are slightly incorrect. The name properties need to be strings, instead of integers:
class Guardian
{
[JsonProperty(PropertyName = "guardian_id")]
public int ID { get; set; }
[JsonProperty(PropertyName = "guardian_name")]
public string Name { get; set; } // <-- This
}
class Patient
{
[JsonProperty(PropertyName = "patient_id")]
public int ID { get; set; }
[JsonProperty(PropertyName = "patient_name")]
public string Name { get; set; } // <-- This
}
Once you've corrected that, you can deserialize the JSON string into two lists of different types. In your case, List<Guardian> and List<Patient> respectively:
string json = #"[{'guardian_id':'1453','guardian_name':'Foo Bar','patient_id':'938','patient_name':'Foo Bar'}]";
var guardians = JsonConvert.DeserializeObject<List<Guardian>>(json);
var patients = JsonConvert.DeserializeObject<List<Patient>>(json);
It you want to do it with 1 call, you need to create a class that matches the JSON. That class can then return Guardian and Patient objects as needed. Also you'll need to use an array or list for the return type because the source JSON is an array.
The class to create:
public class Pair
{
public Pair()
{
Guardian = new Guardian();
Patient = new Patient();
}
[JsonIgnore]
public Guardian Guardian { get; set; }
[JsonIgnore]
public Patient Patient { get; set; }
[JsonProperty(PropertyName = "guardian_id")]
public int GuardianID
{
get { return Guardian.ID; }
set { Guardian.ID = value; }
}
[JsonProperty(PropertyName = "guardian_name")]
public string GuardianName
{
get { return Guardian.Name; }
set { Guardian.Name = value; }
}
[JsonProperty(PropertyName = "patient_id")]
public int PatientID
{
get { return Patient.ID; }
set { Patient.ID = value; }
}
[JsonProperty(PropertyName = "patient_name")]
public string PatientName
{
get { return Patient.Name; }
set { Patient.Name = value; }
}
}
And how to use it:
var pairs = JsonConvert.DeserializeObject<Pair[]>(response.Content);
if (pairs.Any())
{
var pair = pairs[0];
Console.WriteLine(pair.Guardian.Name);
Console.WriteLine(pair.Patient.Name);
}
Not in one call, and it seems the data is an array, so you need a little more work.
Zip is the key method here to join the two separate object lists:
Guardian[] guardians = JsonConvert.DeserializeObject<Guardian[]>(response.Content);
Patient[] patients = JsonConvert.DeserializeObject<Patient[]>(response.Content);
var combined = guardians.Zip(patients, (g, p) => Tuple.Create(g, p)).ToList();
It would be far more easier to just read the JSON at once, it a single object.
It can't be done with 1 call with the types that you show. You can try using the generic <T> approach for each type, also you'll need to use arrays or lists for the return type because the source JSON is an array:
var guardians = JsonConvert.DeserializeObject<Guardian[]>(response.Content);
var patients = JsonConvert.DeserializeObject<Patient[]>(response.Content);
And then combine the two if you need them to be paired. E.g. if you are sure that you always have just one of each:
var pair = new Pair(guardians[0], patients[0]);
You could make a type to house the two subobjects:
[JsonConverter(typeof(GuardianPatientConverter))]
class GuardianPatient
{
public Guardian Guardian { get; set; }
public Patient Patient { get; set; }
}
And then create a JSON converter to handle the JSON:
class GuardianPatientConverter : JsonConverter
{
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return typeof(GuardianPatient) == objectType;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
var jObject = JObject.Load(reader);
var guardian = new Guardian();
var patient = new Patient();
serializer.Populate(jObject.CreateReader(), guardian);
serializer.Populate(jObject.CreateReader(), patient);
return new GuardianPatient()
{
Guardian = guardian,
Patient = patient
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And then you can use it like so:
var json = "[{\"guardian_id\":\"1453\",\"guardian_name\":\"Foo Bar\",\"patient_id\":\"938\",\"patient_name\":\"Foo Bar\",}]";
var objects = JsonConvert.DeserializeObject<IEnumerable<GuardianPatient>>(json);
and if you want it as an array of pairs:
var objects = JsonConvert.DeserializeObject<IEnumerable<GuardianPatient>>(json)
.Select(o => new Pair(o.Guardian, o.Patient))
.ToArray();
This won't make it any faster, but I suspect you're looking for an easier way to work with the JSON.
One another approach would be creating class that matches JSON format, i.e. class with four properties with corresponding names. Then, deserialize JSON into that class and then use it in your code (set properties of objects with values from JSON, pass deserialized object to constructor of another class).
In your models, The name properties need to be strings, instead of integers. After correcting it.
You can use Tuple class
string json = #"[{'guardian_id':'1453','guardian_name':'Foo Bar','patient_id':'938','patient_name':'Foo Bar'}]";
var combination = new Tuple<List<Guardian>, List<Patient>>(JsonConvert.DeserializeObject<List<Guardian>>(json), JsonConvert.DeserializeObject<List<Patient>>(json));
static void Main(string[] args)
{
string json = JsonConvert.SerializeObject(new[]
{
new
{
guardian_id = "1453",
guardian_name = "Foo Bar",
patient_id = "938",
patient_name = "Bar Foo",
}
});
Guardian[] guardians = JsonConvert.DeserializeObject<Guardian[]>(json);
Patient[] patients = JsonConvert.DeserializeObject<Patient[]>(json);
}
Since both your objects are the same, wouldn't it make more sense to just have an ID/Name structure of a single base class? If you need to send all the data at the same time, you can restructure your data and use a data transfer object pattern. The JSON object would become
[{
"guardian": {
"id": "1453",
"name": "Foo Bar"
},
"patient": {
"id" : "938",
"name": "Foo Bar"
}
}]
And your corresponding data objects would be:
public class Record {
public int id { get; set; } // or string. I'm not sure which would be more appropriate
public string name { get; set;}
}
and
public class RecordDto {
public Record guardian { get; set; }
public Record patient { get; set; }
}
And your API would receive a
List<RecordDto>
parameter (since you are passing an array of objects).

Convert class to dynamic and add properties

I have a class MyClass. I would like to convert this to a dynamic object so I can add a property.
This is what I had hoped for:
dynamic dto = Factory.Create(id);
dto.newProperty = "123";
I get the error:
WEB.Models.MyClass does not contain a definition for 'newProperty'
Is that not possible?
The following has worked for me in the past:
It allows you to convert any object to an Expando object.
public static dynamic ToDynamic<T>(this T obj)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var propertyInfo in typeof(T).GetProperties())
{
var currentValue = propertyInfo.GetValue(obj);
expando.Add(propertyInfo.Name, currentValue);
}
return expando as ExpandoObject;
}
Based on: http://geekswithblogs.net/Nettuce/archive/2012/06/02/convert-dynamic-to-type-and-convert-type-to-dynamic.aspx
As my object has JSON specific naming, I came up with this as an alternative:
public static dynamic ToDynamic(this object obj)
{
var json = JsonConvert.SerializeObject(obj);
return JsonConvert.DeserializeObject(json, typeof(ExpandoObject));
}
For me the results worked great:
Model:
public partial class Settings
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("runTime")]
public TimeSpan RunTime { get; set; }
[JsonProperty("retryInterval")]
public TimeSpan RetryInterval { get; set; }
[JsonProperty("retryCutoffTime")]
public TimeSpan RetryCutoffTime { get; set; }
[JsonProperty("cjisUrl")]
public string CjisUrl { get; set; }
[JsonProperty("cjisUserName")]
public string CjisUserName { get; set; }
[JsonIgnore]
public string CjisPassword { get; set; }
[JsonProperty("importDirectory")]
public string ImportDirectory { get; set; }
[JsonProperty("exportDirectory")]
public string ExportDirectory { get; set; }
[JsonProperty("exportFilename")]
public string ExportFilename { get; set; }
[JsonProperty("jMShareDirectory")]
public string JMShareDirectory { get; set; }
[JsonIgnore]
public string Database { get; set; }
}
I used it in this manner:
private static dynamic DynamicSettings(Settings settings)
{
var settingsDyn = settings.ToDynamic();
if (settingsDyn == null)
return settings;
settingsDyn.guid = Guid.NewGuid();
return settingsDyn;
}
And received this as a result:
{
"id": 1,
"runTime": "07:00:00",
"retryInterval": "00:05:00",
"retryCutoffTime": "09:00:00",
"cjisUrl": "xxxxxx",
"cjisUserName": "xxxxx",
"importDirectory": "import",
"exportDirectory": "output",
"exportFilename": "xxxx.xml",
"jMShareDirectory": "xxxxxxxx",
"guid": "210d936e-4b93-43dc-9866-4bbad4abd7e7"
}
I don't know about speed, I mean it is serializing and deserializing, but for my use it has been great. A lot of flexability like hiding properties with JsonIgnore.
Note: xxxxx above is redaction. :)
You cannot add members to class instances on the fly.
But you can use ExpandoObject. Use factory to create new one and initialize it with properties which you have in MyClass:
public static ExpandoObject Create(int id)
{
dynamic obj = new ExpandoObject();
obj.Id = id;
obj.CreatedAt = DateTime.Now;
// etc
return obj;
}
Then you can add new members:
dynamic dto = Factory.Create(id);
dto.newProperty = "123";
You can't add properties to types at runtime. However, there is an exception which is: ExpandoObject. So if you need to add properties at runtime you should use ExpandoObject, other types don't support this.
Just to add up my experience, if you are using JSON.NET, then below might be one of the solution:
var obj....//let obj any object
ExpandoObject expandoObject= JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(obj));
Not tested performances etc.. but works.

How to convert HttpResponseMessage having OData to a C# object?

I am calling a REST service from my C# application which connects to CRM.
This returns HttpResponseMessage.
response.Content.ReadAsStringAsync().Result
The above statement returns following output. I need to convert this to Account object, which already has "accountnumber, and accountid properties.
{
"#odata.context":"https://APIURL/api/data/v8.1/$metadata#account(accountnumber)","value":[
{
"#odata.etag":"W/\"12496866\"","accountnumber":"D00208","accountid":"30417c0f-7b8c-e611-80f3-5065f38bd4d1"
} ] }
I have tried following code
Account return = JsonConvert.DeserializeObject<Account>(response.Content.ReadAsStringAsync().Result);
But this doesn't fill up the object, and it always has null values in accountnumber, and accountid fields.
Any idea of how to properly convert this response to the C# type.
you should do it like this -
public class Value
{
[JsonProperty("#odata.etag")]
public string etag { get; set; }
public string accountnumber { get; set; }
public string accountid { get; set; }
}
public class RootObject
{
[JsonProperty("#odata.context")]
public string context { get; set; }
public List<Value> value { get; set; }
}
then deserialize-
var value = JsonConvert.DeserializeObject<RootObject>(json);
We can parse and create Anonymous Type based on that. In your case, replace the Anonymous Type with Account object.
Given the JSON string:
string json = #"{
'#odata.context':'https://APIURL/api/data/v8.1/$metadata#account(accountnumber)',
'value':[
{
'#odata.etag':'W/\'12496866\'',
'accountnumber':'D00208',
'accountid':'30417c0f-7b8c-e611-80f3-5065f38bd4d1'
}
]
}";
It can be parsed as below:
var jsonObject = JObject.Parse(json);
var dataObject = new
{
Context = jsonObject["#odata.context"],
Values = jsonObject["value"].AsEnumerable<JToken>()
.Select(v => new
{
ETag = v["#odata.etag"],
AccountNumber = v["accountnumber"],
AccountId = v["accountid"]
}).ToArray()
};
In order to convert to Account object where the object is defined as below:
public class Account
{
public string Number { get; set; }
public string Id { get; set; }
}
Then the JSON object can be parsed as below (if looking for only first node; It can also be converted to list of Accounts:
var jsonObject = JObject.Parse(json);
var account = jsonObject["value"].AsEnumerable<JToken>()
.Select(v => new Account()
{
Number = v["accountnumber"].ToString(),
Id = v["accountid"].ToString()
}).FirstOrDefault();
You can generalize the accepted answer by using a generic class to deserialize json web response:
class RootObject<T>
{
public List<T> Value { get; set; }
}
var odata = JsonConvert.DeserializeObject<RootObject<POCO>>(json);
Try it with live Demo

C# deserialize dynamic JSON

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.

JavaScriptDeseializer : Can not serialize array

My application is asp.net. I have to send some values back to server. For this I create a object serialize it and send it to server. At server I try to de-serialize it
Following is my code
[Serializable]
public class PassData
{
public PassData()
{
}
public List<testWh> SelectedId { get; set; }
public string SelectedControlClientId { get; set; }
public string GroupTypeId { get; set; }
public string SectionTypeId { get; set; }
}
[Serializable]
public class testWh
{
public testWh()
{
}
public string Id { get; set; }
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
//this can not serialize the SelectedId and the count remains 0
PassData data = serializer.Deserialize<PassData>(jsonString);
//this serialize in an anonymous object with key value pair
var data2 = serializer.DeserializeObject(textHiddenArguments.Text);
Following is my Json Serialized String
{
"SelectedId":{"0":"ABCD","1":"JKLM"},
"SelectedControlClientId":"YTUTOOO",
"GroupTypeId":3,
"SectionTypeId":"1"
}
quotes escaped string
"{\"SelectedId\":{\"0\":\"ABCD\",\"1\":\"JKLM\"},\"SelectedControlClientId\":\"YTUTOOO\",\"GroupTypeId\":3,\"SectionTypeId\":\"1\"}"
My Problem is Selected Id is array of testWH object. But when I try to desrialize it, the SelectedId property of PassData which is list does not get serialized and count remains zero.
I tried using array instead of List, which gave an exception "no parameter less constructor..."
Could any one explain the what I am doing wrong here ?
The key problem here is that the JSON doesn't match the objects you have constructed. You can see this by writing the data you want and serializing:
var obj = new PassData
{
SelectedId = new List<testWh>
{
new testWh { Id = "ABCD"},
new testWh { Id = "JKLM"}
},
GroupTypeId = "3",
SectionTypeId = "1",
SelectedControlClientId = "YTUTOOO"
};
string jsonString = serializer.Serialize(obj);
which gives JSON like:
{"SelectedId":[{"Id":"ABCD"},{"Id":"JKLM"}],
"SelectedControlClientId":"YTUTOOO","GroupTypeId":"3","SectionTypeId":"1"}
So now you need to decide which you want to change; the JSON or the classes. The following alternative class works fine with your original JSON, for example:
public class PassData
{
public Dictionary<string,string> SelectedId { get; set; }
public string SelectedControlClientId { get; set; }
public string GroupTypeId { get; set; }
public string SectionTypeId { get; set; }
}

Categories