deserializing object with composition when using nested lists - c#

I have an object that contains lists of other objects and that looks like this:
public class MyObject {
public int Prop1 { get; set; }
public List<Object1> TheListOfObject1 { get; set; }
public List<Object2> TheListOfObject2 { get; set; }
public string MyObjectInJson { get; set;}
public void MyObjectToJson()
{
JavascriptSerializer TheSerializer = new JavascriptSerializer();
TheSerializer.RegisterConverters(new JavaScriptConverter[] { new Object1ToJson() });
TheSerializer.RegisterConverters(new JavaScriptConverter[] { new Object2ToJson() });
MyObjectInJson = TheSerializer.Serialize(this);
}
Now I have another class that's getting a json string of MyObject and I need to deserializse the string and create a MyObject from the string.
I know there's JSON.net and other library available but I want to use .net's JavascriptSerializer.
Suppose that the converters I have also handle the deserializtion. Do I simply do something like this:
1) add FromJson method to MyObject
public this MyObjectFromJson (string MyObjectInJson)
{
JavascriptSerializer TheSerializer = new JavascriptSerializer();
TheSerializer.RegisterConverters(new JavaScriptConverter[] { new Object1ToJson() });
TheSerializer.RegisterConverters(new JavaScriptConverter[] { new Object2ToJson() });
this = TheSerializer.DeSerialize(MyObjectInJson);
}
2) and in the calling class write this:
MyObject TheObject = new MyObject();
TheObject = TheObject.MyObjectFromJson(TheIncomingString);
I'm not sure how to proceed. Will this kind of approach work?
Thanks.

Unless your lists of Object1 and Object2 are incredibly complex, you probably don't need the Converters.
Here is a quick sample that I threw together based on your code. Note that the deserializer is static since you will want it to create a new object and you can't set this because it is readonly.
public class MyObject
{
public int Prop1 { get; set; }
public List<Object1> TheListOfObject1 { get; set; }
public List<Object2> TheListOfObject2 { get; set; }
public MyObject()
{
TheListOfObject1 = new List<Object1>();
TheListOfObject2 = new List<Object2>();
}
public string ToJson()
{
JavaScriptSerializer TheSerializer = new JavaScriptSerializer();
return TheSerializer.Serialize(this);
}
public static MyObject FromJson(string sValue)
{
JavaScriptSerializer TheSerializer = new JavaScriptSerializer();
return TheSerializer.Deserialize<MyObject>(sValue);
}
}
This is then called by
MyObject oObject = new MyObject();
oObject.TheListOfObject1.Add(new Object1(1));
oObject.TheListOfObject2.Add(new Object2(2));
oObject.Prop1 = 3;
string sJSON = oObject.ToJson();
System.Diagnostics.Debug.WriteLine(sJSON);
oObject = MyObject.FromJson(sJSON);
System.Diagnostics.Debug.WriteLine(oObject.Prop1);

Related

.NET - Omit Fields from JSON Web Service Call

I'm working on a .NET application for my company to interact with the Nutshell CRM. They have documentation provided for their JSON API here. I'm slowly building out all the classes in my application, but I've run into the issue of only needing to update one field on a call, but having the application include every field that I have on that class.
So for a condensed example of the editLead method, where I'm only modifying the customFields:
Nutshell documentation states that all fields are optional. My classes are set up as the following, where my custom fields in Nutshell are Division, Product, Country:
public class editLead
{
public Customfields customFields { get; set; }
}
public class Customfields
{
public string Division { get; set; }
public string Product { get; set; }
public string Country { get; set; }
}
EDIT (adding more code):
[DataContract(Name = "params")]
public class EditLeadParams
{
public string leadId { get; set; }
public editLead lead { get; set; }
public string rev { get; set; }
}
I'm using RestSharp to make the following call:
var editleadclient = new RestClient();
Method editleadMethod = new Method();
editleadMethod = Method.POST;
var editleadrequest = new RestRequest(editleadMethod);
editleadrequest.RequestFormat = DataFormat.Json;
editleadclient.BaseUrl = new Uri(apiuri);
editleadrequest.Credentials = new NetworkCredential(login, apikey);
leadJSON.EditLeadParams lead1 = new leadJSON.EditLeadParams()
{
leadId = foundlead[0],
lead = new leadJSON.editLead()
{
customFields = new leadJSON.Customfields()
{
Division = "AMERICAS",
}
},
rev = foundlead[1],
};
leadJSON.EditLeadRequest editreq = new leadJSON.EditLeadRequest()
{
#params = lead1,
method = "editLead",
};
editleadrequest.AddBody(editreq);
IRestResponse editResponse = editleadclient.Execute(editleadrequest);
If I only want to update the Division, it will use the following JSON {"customFields":{"Division":"AMERICAS","Product":null,"Country":null}}, and overwrite the Product and Country fields and make them blank. However, if I comment out the Product and Country, in the Customfields definition, it will update the Division and leave the Product and Country alone.
Is there another way to define these classes so that I can have it all defined, but only update what needs to be?
Declaration:
//JsonSerializer.cs
public static class JsonSerializer
{
public static string Serialize(object target, bool ignoreNulls = true)
{
var javaScriptSerializer = new JavaScriptSerializer();
if (ignoreNulls)
{
javaScriptSerializer.RegisterConverters(new[]
{
new NullExclusionConverter(target)
});
}
return javaScriptSerializer.Serialize(target);
}
}
//NullExclusionConverter.cs
public class NullExclusionConverter : JavaScriptConverter
{
private readonly Type _type;
public NullExclusionConverter(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this._type = target.GetType();
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { this._type };
}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
if (obj == null)
{
return result;
}
var properties = obj.GetType().GetProperties();
foreach (var propertyInfo in properties)
{
//Use propertyInfo.Name to exclude a specific property name
if (propertyInfo.GetValue(obj, null) == null)
{
continue;
}
result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
}
return result;
}
}
Usage:
string jsonString = JsonSerializer.Serialize(objectToSerialize);
Add a reference to System.Web.Extensions
I am leaving my initial answer because it does return only non-null properties as a Json string. However here is your answer when using RestSharp.
On your request add:
editleadrequest.JsonSerializer.Options = new SerializerOptions()
{
SkipNullProperties = true
};

Alternative for switch statement in c#

Can someone suggest an alternative way to solve this problem, I don't want to use SWITCH statement in my code.
Class Definition:
public class Rootobject
{
public Must[] must { get; set; }
public Should[] should { get; set; }
}
public class Should
{
public Match match { get; set; }
public Bool _bool { get; set; }
}
public class Must
{
public Match match { get; set; }
public Bool _bool { get; set; }
}
public class Match
{
public string pname { get; set; }
}
public class Bool
{
public string rname { get; set; }
}
Function Definition
public root getobject(string op)
{
Rootobject root = new Rootobject();
op ="must";
switch (op)
{
case "should":
root.should = new Should[1];
Should objShould = new Should();
objShould.match = new Match();
objShould.match.pname = "hello";
root.should[0] = objShould;
break;
case "must":
root.must = new Must[1];
Must objMust = new Must();
objMust.match = new Match();
objMust.match.pname = "hello";
root.must[0] = objMust;
break;
}
return(root);
}
Switch statement is an overhead an new type comes then i may need to add another condition. Can anyone suggest an alternative way of using switch statement.
Based on the comments under your question, I discovered it is possible to implement what #Jon Skeet stated.
You can add an Initialize Method in your RootObject class to create the dictionary (Use a ref Dictionary so to avoid setting the dictionary in your RootObject class that could change the structure of your serialization):
public void Initialize(ref Dictionary<string, Func<Rootobject>> rootDic)
{
Func<Rootobject> shouldFunc = () =>
{
Rootobject root = new Rootobject();
root.should = new Should[1];
Should objShould = new Should();
objShould.match = new Match();
objShould.match.pname = "hello";
root.should[0] = objShould;
return root;
};
Func<Rootobject> mustFunc = () =>
{
Rootobject root = new Rootobject();
root.must = new Must[1];
Must objMust = new Must();
objMust.match = new Match();
objMust.match.pname = "hello";
root.must[0] = objMust;
return root;
};
rootDic.Add("should", shouldFunc);
rootDic.Add("must", mustFunc);
}
And then call it in your getobject method like so:
public static Rootobject getobject(string op)
{
Dictionary<string, Func<Rootobject>> rootDic = new Dictionary<string,Func<Rootobject>>();
Rootobject root = new Rootobject();
root.Initialize(ref rootDic);
if(rootDic.Count > 0)
return rootDic[op].Invoke();
return new Rootobject();
}
You still going to get the same result as the solution in your question even after serializing it.

serialize and deserialize self reference object in c#

I have a class A like this
class A
{
public string Type { get; set; }
public object[] Content { get; set; }
public string[] jsonContent { get; set; }
public A()
{
}
public A(string type)
{
this.Type = type;
}
public A(string type, object[] content)
{
this.Type = type;
this.Content = content;
}
public string ToJson()
{
int len = Content.Length;
string[] jsonContentTmp = new string[len];
for (int i = 0; i < Content.Length; ++i)
{
jsonContentTmp[i] = JsonConvert.SerializeObject(Content[i]);
}
jsonContent = jsonContentTmp;
var json = JsonConvert.SerializeObject(this);
return json;
}
public static A ToA(string str)
{
Request a = JsonConvert.DeserializeObject<A>(str);
return a;
}
}
Consider bellow:
A sub1 = new A();
A sub2 = new A();
object[] obj = {sub1, sub2};
A test = new A("type", obj);
When I want to serialize test, I receive exception
self reference
I tried PreserveReferencesHandling but i couldn't deserialize and receive exception
'cannot preserve reference toarray'
.
Any idea to serialize and deserialize it?
So it seems this is done on purpose to prevent Stackoverflow exceptions. No pun intended. You have to turn PreserveReferences on, to enable self referencing:
Serialising Circular references
In your AppStart in Global.asax try the following:
var jsonSerializerSettings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonNetFormatter(jsonSerializerSettings));

Create JSON with C# Object

I am trying to create the following JSON data:
{
'chart.labels': ['Bob','Lucy','Gary','Hoolio'],
'chart.tooltips': ['Bob did well',
'Lucy had her best result',
'Gary - not so good',
'Hoolio had a good start'
]
}
I am using C# and trying to create an object in order to do this.....something like:
public class chart{
public string[] chart.labels {get;set;}
public string[] chart.tooltips {get;set;}
}
but obviously I cannot have properties containing spaces.
How would I go about doing this ?
UPDATE:
Using JamieC's answer the following works perfecly
public virtual ActionResult CompanyStatus()
{
var labelList = new List<string>() { "Bob", "Lucy", "Gary", "Hoolio" };
var tooltipsList = new List<string>() { "Bob did well", "Lucy had her best result", "Gary - not so good", "Hoolio had a good start" };
var cData = new chartData()
{
Labels = labelList.ToArray(),
Tooltips = tooltipsList.ToArray()
};
var serializer = new DataContractJsonSerializer(cData.GetType());
String output;
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, cData);
output = Encoding.Default.GetString(ms.ToArray());
}
return this.Content(output);
}
[DataContract]
public class chartData
{
[DataMember(Name = "chart.labels")]
public string[] Labels { get; set; }
[DataMember(Name = "chart.tooltips")]
public string[] Tooltips { get; set; }
}
}
Which produces:
{"chart.labels":["Bob","Lucy","Gary","Hoolio"],"chart.tooltips":["Bob did well","Lucy had her best result","Gary - not so good","Hoolio had a good start"]}
The usual way to do this is to use a DataContractJsonSerializer to turn your object into Json, and use DataMember attributes to annotate what names to use for properties:
[DataContract]
public class ChartModel{
[DataMember(Name = "chart.labels")]
public string[] Labels {get;set;}
[DataMember(Name = "chart.tooltips")]
public string[] Tooltips {get;set;}
}
I personally use my own ActionResult to wrap up the serialization in MVC:
public class JsonDataContractResult : ActionResult
{
public JsonDataContractResult(Object data)
{
this.Data = data;
}
protected JsonDataContractResult()
{
}
public Object Data { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
Guard.ArgumentNotNull(context, "context");
var serializer = new DataContractJsonSerializer(this.Data.GetType());
String output;
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, this.Data);
output = Encoding.Default.GetString(ms.ToArray());
}
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.Write(output);
}
}
And return that from a helper method in a base controller:
public abstract class MyBaseController: Controller
{
protected JsonDataContractResult JsonContract(Object data)
{
return new JsonDataContractResult(data);
}
}
Then my controller becomes really simple:
public class SomeController: MyBaseController
{
public ActionResult SomeAction()
{
var model = new ChartModel()
{
Labels = ...,
Tooltips = ...
};
return JsonContract(model);
}
}
You can use JSON.NET library, you can download it from here
It has this feature:
Attribute property name customization
This question will help you:
Json.Net: JsonSerializer-Attribute for custom naming
And you can use DataContractJsonSerializer it provides this feature, but JavaScriptSerializer is not.
For MVC project Newtonsoft.Json library is available.(You have to manually include this for other projects)
So give JsonProperty in the model, like this...
public class ChartModel{
[JsonProperty("chart.labels")]
public string[] Labels {get;set;}
[JsonProperty("chart.tooltips")]
public string[] Tooltips {get;set;}
}
and use Newtonsoft.Json.JsonConvert.SerializeObject(object); or Json.Encode(object) to convert to JSON.

Discover output class from json.net

I'm doing a project where I dynamically build a set of objects based on reflection and serialize it (using json.net).
What I want to do is to deserialize it and recreate the object tree, but I don't know the final class type.
So how can I find out?
Here's an example:
public class insideBleah
{
public int BProperty
{ get; set; }
}
public class bleah
{
public int AProperty
{ get; set; }
public insideBleah Inside
{ get; set; }
}
and
var bleah = new bleah();
bleah.AProperty = 1;
bleah.Inside = new insideBleah();
bleah.Inside.BProperty = 2;
var output = JsonConvert.SerializeObject(bleah, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects
});
This produces the output string:
"{\"$type\":\"jsontest.bleah, jsontest\",\"AProperty\":1,\"Inside\":{\"$type\":\"jsontest.insideBleah, jsontest\",\"BProperty\":2}}"
So I can see the class in there. It's so close! But I can't seem to tease the information out.
How can I do this? I can't do:
var newObject = (bleah)JsonConvert.DeserializeObject<bleah>(output);
because I don't know it's a 'bleah'.
How can I handle this?
Thanks in advance
Why can you just use:
using System;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
class Program
{
private static void Main(string[] args)
{
var bleah = new Person();
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects };
var output = JsonConvert.SerializeObject(bleah, settings);
Console.WriteLine(output);
var deserializeObject = JsonConvert.DeserializeObject(output, settings);
Console.WriteLine(deserializeObject.GetType().Name);
}
}
class Person
{
public string Name { get; set; }
}
}
The output:
{"$type":"ConsoleApplication1.Person, ConsoleApplication1","Name":null}
Person

Categories

Resources