How to handle deserialization of empty string into long in .NET? - c#

The below illustration represents building Object of type TestClass2 using object of type TestClass1 with the help of Serialization/Deserialization.
TestClass1 and TestClass2 have the same structure except one of the members is string in TestClass1 but long in TestClass2.
public class TestClass1
{
public string strlong;
}
public class TestClass2
{
public long strlong;
}
TestClass1 objT1 = new TestClass1();
objT1.strlong = "20134567";
TestClass2 objT2;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string JSON1 = serializer.Serialize(objT1);
objT2 = serializer.Deserialize<TestClass2>(JSON1);
After the operation, objT2 will have the values of objT1 but strlong will now be long as opposed to string.
The problem is, if the strlong value in objT1 is an empty string --> "", the deserialization fails with an exception "" is not a valid value for Int64.
If strlong is non empty string with just numeric characters, the current deserialization works. But I do not know the workaround when something like empty string appears.
For now, lets assume that
strlong will be in the range of long
Will just be a sequence of numeric characters i.e. it will not have . or , or / or any type of other characters
Have access to only objects for serialization and I cannot make modifications to TestClass1 or TestClass2.
If there is a simple way (or not) of Creating objects of one class using objects of another class, please mention that in the comments.
EDIT-Extending the logic
To extend the logic of solution given in the Answer below to Classes containing members of type other classes, I have used the serialization solution given below to the member items as well. In other words, if classes contain members of other classes, is there a better way of handling the deeper levels than the code below?
// **Item1 :**
// These are the subclasses and classes
// whose objects I am trying to serialize
// and deserialize from one type to another
public class SubClass1
{
public string toomuch;
public int number = 30;
}
public class SubClass2
{
public long toomuch;
public int number;
}
public class TestClass1
{
public string strlong;
public SubClass1 item2;
}
public class TestClass2
{
public long strlong;
public SubClass2 item2;
}
// **Item2 :**
// Solution from StackOverflow for serialization of
// empty string
public class TestClass1Converter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new Type[] { typeof(TestClass1) }; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var data = obj as TestClass1;
var dic = new Dictionary<string, object>();
if (data == null)
{
return dic;
}
long val = 0;
long.TryParse(data.strlong, out val);
dic.Add("strlong", val);
// **Item3 :**
// trying to serialize and deserialize item2 which is of type SubClass1
// which might also have empty string
/*******************/
JavaScriptSerializer subClassSerializer = new JavaScriptSerializer();
subClassSerializer.RegisterConverters(new[] { new SubClass1Converter() });
string JSONstr = subClassSerializer.Serialize(data.item2);
dic.Add("item2", subClassSerializer.Deserialize<SubClass2>(JSONstr));
/*******************/
return dic;
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
// **Item4 :**
// Serialization for subclass
public class SubClass1Converter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new Type[] { typeof(SubClass1) }; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var data = obj as SubClass1;
var dic = new Dictionary<string, object>();
if (data == null)
{
return dic;
}
long val = 0;
long.TryParse(data.toomuch, out val);
dic.Add("toomuch", val);
dic.Add("number", data.number);
return dic;
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
TestClass1 objT1 = new TestClass1();
objT1.strlong = "";
SubClass1 objSub = new SubClass1();
objSub.toomuch = "";
objT1.item2 = objSub;
TestClass2 objT2;
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new TestClass1Converter() });
string JSON1 = serializer.Serialize(objT1);
objT2 = serializer.Deserialize<TestClass2>(JSON1);
}
}

You should declare your TestClass2.strlong as nullable.
public class TestClass2
{
public long? strlong;
}
Now you can have null in case when the TestClass1.strlong is empty string or null.
Here is UPDATE in case that you haven't access to modify the classes.
You should add to the serializer the converter via RegisterConverters to customize conversion. Here is the example:
public class TestClass1Converter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new Type[] { typeof(TestClass1)}; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var data = obj as TestClass1;
var dic = new Dictionary<string, object>();
if(data == null)
{
return dic;
}
long val = 0;
long.TryParse(data.strlong, out val);
dic.Add("strlong", val);
return dic;
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
This converter will serialize strlong to 0 in case when it is not convertible to long. You can use it in this way:
TestClass1 objT1 = new TestClass1();
objT1.strlong = "444";
TestClass2 objT2;
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new [] {new TestClass1Converter()});
string JSON1 = serializer.Serialize(objT1);
objT2 = serializer.Deserialize<TestClass2>(JSON1);

Related

Issue while deserializing Json's Multidimensional array field using System.Web.Script.Serialization.JavaScriptSerializer custom converter

Hi I had an issue while deserializing a json file which can have different data type( float and float array). I got a suggestion to use custom converter from Deserialize a json field with different data types without using Newtonsoft json but with System.Web.Script.Serialization.JavaScriptSerializer and it works fine for one dimensional array. I am currently being given jsons with two dimensional array and this converter couldn't handle the same. Below is a snippet from my json
{
"name" : "foo",
"value" : 457,
"comment" : "bla bla bla",
"data" : [
{
"name" : "bar",
"max" : 200,
"default" : [
[7,4],[2,2],[7,4],[1,1],[2,3],[3,1],[7,9]
]
}
]
}
Where the default can be sometimes primitive like
"default" : 3.56
Edit : Code used for custom serialization
class RootObjectConverter : CustomPropertiesConverter<RootObject>
{
const string ValuesName = "values";
protected override IEnumerable<string> CustomProperties
{
get { return new[] { ValuesName }; }
}
protected override void DeserializeCustomProperties(Dictionary<string, object> customDictionary, RootObject obj, JavaScriptSerializer serializer)
{
object itemCost;
if (customDictionary.TryGetValue(ValuesName, out itemCost) && itemCost != null)
obj.Values = serializer.FromSingleOrArray<float>(itemCost).ToArray();
}
protected override void SerializeCustomProperties(RootObject obj, Dictionary<string, object> dict, JavaScriptSerializer serializer)
{
obj.Values.ToSingleOrArray(dict, ValuesName);
}
}
public abstract class CustomPropertiesConverter<T> : JavaScriptConverter
{
protected abstract IEnumerable<string> CustomProperties { get; }
protected abstract void DeserializeCustomProperties(Dictionary<string, object> customDictionary, T obj, JavaScriptSerializer serializer);
protected abstract void SerializeCustomProperties(T obj, Dictionary<string, object> dict, JavaScriptSerializer serializer);
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
// Detach custom properties
var customDictionary = new Dictionary<string, object>();
foreach (var key in CustomProperties)
{
object value;
if (dictionary.TryRemoveInvariant(key, out value))
customDictionary.Add(key, value);
}
// Deserialize and populate all members other than "values"
var obj = new JavaScriptSerializer().ConvertToType<T>(dictionary);
// Populate custom properties
DeserializeCustomProperties(customDictionary, obj, serializer);
return obj;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
// Generate a default serialization. Is there an easier way to do this?
var defaultSerializer = new JavaScriptSerializer();
var dict = defaultSerializer.Deserialize<Dictionary<string, object>>(defaultSerializer.Serialize(obj));
// Remove default serializations of custom properties, if present
foreach (var key in CustomProperties)
{
dict.RemoveInvariant(key);
}
// Add custom properties
SerializeCustomProperties((T)obj, dict, serializer);
return dict;
}
public override IEnumerable<Type> SupportedTypes
{
get { return new[] { typeof(T) }; }
}
}
public static class JavaScriptSerializerObjectExtensions
{
public static void ReplaceInvariant<T>(this IDictionary<string, T> dictionary, string key, T value)
{
RemoveInvariant(dictionary, key);
dictionary.Add(key, value);
}
public static bool TryRemoveInvariant<T>(this IDictionary<string, T> dictionary, string key, out T value)
{
if (dictionary == null)
throw new ArgumentNullException();
var keys = dictionary.Keys.Where(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase)).ToArray();
if (keys.Length == 0)
{
value = default(T);
return false;
}
else if (keys.Length == 1)
{
value = dictionary[keys[0]];
dictionary.Remove(keys[0]);
return true;
}
else
{
throw new ArgumentException(string.Format("Duplicate keys found: {0}", String.Join(",", keys)));
}
}
public static void RemoveInvariant<T>(this IDictionary<string, T> dictionary, string key)
{
if (dictionary == null)
throw new ArgumentNullException();
foreach (var actualKey in dictionary.Keys.Where(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase)).ToArray())
dictionary.Remove(actualKey);
}
public static void ToSingleOrArray<T>(this ICollection<T> list, IDictionary<string, object> dictionary, string key)
{
if (dictionary == null)
throw new ArgumentNullException();
if (list == null || list.Count == 0)
dictionary.RemoveInvariant(key);
else if (list.Count == 1)
dictionary.ReplaceInvariant(key, list.First());
else
dictionary.ReplaceInvariant(key, list.ToArray());
}
public static List<T> FromSingleOrArray<T>(this JavaScriptSerializer serializer, object value)
{
if (value == null)
return null;
if (value.IsJsonArray())
{
return value.AsJsonArray().Select(i => serializer.ConvertToType<T>(i)).ToList();
}
else
{
return new List<T> { serializer.ConvertToType<T>(value) };
}
}
public static bool IsJsonArray(this object obj)
{
if (obj is string || obj is IDictionary)
return false;
return obj is IEnumerable;
}
public static IEnumerable<object> AsJsonArray(this object obj)
{
return (obj as IEnumerable).Cast<object>();
}
}
and used it like
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new RootObjectConverter() });
var root = serializer.Deserialize<RootObject>(json);
Can anyone help me on how to proceed on this?
I fixed the issue by using a Dictionary instead of a class object for parsing different data type fields and accessing the respective property with the key value. Thanks Everyone for your suggestions.

Converting boolean to int in json string

I there,
I'm working on a c# application
I Have a situation where i get an object from a web service, say
MyObject{
public bool MyProp
}
And I can't modify that object,
but i need to serialize MyObject to a json string but MyProp has to be converted to 1 or 0 instead of true/false.
I'm using JavaScriptSerializer to serialize to Json
Any idea?
tks
If you are willing to switch to json.net, you can use the solution from Convert an int to bool with Json.Net.
If you wish to continue using JavaScriptSerializer, you will need to create a JavaScriptConverter for your MyObject type as follows:
class MyObjectConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new[] { typeof(MyObject) }; }
}
// Custom conversion code below
const string myPropName = "MyProp";
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
object value;
if (dictionary.TryGetValue(myPropName, out value))
{
dictionary[myPropName] = !value.IsNullOrDefault();
}
var myObj = new JavaScriptSerializer().ConvertToType<MyObject>(dictionary);
return myObj;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var myObj = (MyObject)obj;
// Generate a default serialization. Is there an easier way to do this?
var defaultSerializer = new JavaScriptSerializer();
var dict = defaultSerializer.Deserialize<Dictionary<string, object>>(defaultSerializer.Serialize(obj));
dict[myPropName] = myObj.MyProp ? 1 : 0;
return dict;
}
}
public static class ObjectExtensions
{
public static bool IsNullOrDefault(this object value)
{
// Adapted from https://stackoverflow.com/questions/6553183/check-to-see-if-a-given-object-reference-or-value-type-is-equal-to-its-default
if (value == null)
return true;
Type type = value.GetType();
if (!type.IsValueType)
return false; // can't be, as would be null
if (Nullable.GetUnderlyingType(type) != null)
return false; // ditto, Nullable<T>
object defaultValue = Activator.CreateInstance(type); // must exist for structs
return value.Equals(defaultValue);
}
}
Then use it like:
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new MyObjectConverter() } );
var json = serializer.Serialize(myObject);
Note - even though your MyObject class only has one property, I wrote the converter under the assumption that in real life it could have additional properties that should be serialized and deserialized automatically, for instance:
public class MyObject
{
public bool MyProp { get; set; }
public string SomeOtherProperty { get; set; }
}

How to override JavaScriptSerializer.Deserialize<T>()

I get a json string which have few data uniformity issue.
For example one field in json string returns a list of string while the same field in other json string returns a dictionary(key, value pairs).
My class which holds the parsed json values have property for the field as List.
Because of this data uniformity problem, the json string is not parsed properly.
Following is my code to parse the json string
JavaScriptSerializer serializer = new JavaScriptSerializer();
myClass mc = serializer.Deserialize<myClass>(jsonString);
IS there any way with which i can write custom code to parse the json string and map it to myClass?
You don't give a concrete example of what you are trying to accomplish, which means we need to make up an example ourselves. Consider the following class:
public class myClass
{
public Dictionary<string, string> data { get; set; }
}
And consider the following two JSON strings:
{"data": ["zero", 1, "two"]}
{"data": {"0": "zero", "1":1, "2":"two"}}
It seems like you might like to parse these identically, with the array being converted to a Dictionary<string, string> whose keys are array indices. This can be accomplished with the following JavaScriptConverter:
public class myClassConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var myClass = new myClass();
object data;
if (dictionary.TryGetValue("data", out data))
{
if (data.IsJsonArray())
{
myClass.data = data.AsJsonArray()
.Select((o, i) => new KeyValuePair<int, object>(i, o))
.ToDictionary(p => p.Key.ToString(NumberFormatInfo.InvariantInfo), p => serializer.ConvertToType<string>(p.Value));
}
else if (data.IsJsonObject())
{
myClass.data = data.AsJsonObject()
.ToDictionary(p => p.Key, p => serializer.ConvertToType<string>(p.Value));
}
}
return myClass;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new [] { typeof(myClass) }; }
}
}
public static class JavaScriptSerializerObjectExtensions
{
public static bool IsJsonArray(this object obj)
{
if (obj is string || obj.IsJsonObject())
return false;
return obj is IEnumerable;
}
public static IEnumerable<object> AsJsonArray(this object obj)
{
return (obj as IEnumerable).Cast<object>();
}
public static bool IsJsonObject(this object obj)
{
return obj is IDictionary<string, object>;
}
public static IDictionary<string, object> AsJsonObject(this object obj)
{
return obj as IDictionary<string, object>;
}
}
The IDictionary<string, object> passed to Deserialize() corresponds to the key/value pairs in the JSON object being converted. For a particular key ("data" in this case) the object value will be an IDictionary<string, object> if the value is, in turn, a JSON object, and an IEnumerable (specifically an ArrayList) if the value is a JSON array. By testing the value against the appropriate type, a conversion can be made.
The converter only does deserialization. Use it like so:
var jsonString1 = #"{""data"": [""zero"", 1, ""two""]}";
var jsonString2 = #"{""data"": {""0"": ""zero"", ""1"":1, ""2"":""two""}}";
var deserializer = new JavaScriptSerializer();
deserializer.RegisterConverters(new JavaScriptConverter[] { new myClassConverter() });
var newJson1 = new JavaScriptSerializer().Serialize(deserializer.Deserialize<myClass>(jsonString1));
var newJson2 = new JavaScriptSerializer().Serialize(deserializer.Deserialize<myClass>(jsonString2));
Console.WriteLine(newJson1); // Prints {"data":{"0":"zero","1":"1","2":"two"}}
Console.WriteLine(newJson2); // Prints {"data":{"0":"zero","1":"1","2":"two"}}
Debug.Assert(newJson1 == newJson2); // No assert

Replace Json.Nets Standard Serialization Dictionary with Custom Dictionary globally

Json.Net uses the default .Net Dictionary for Serialization of JSON Dictionaries when i just use the IDictionary interface. I want to replace it against my Custom Version of a Dictionary globally.
Do I need to write a JsonConverter in order to do this or do i just miss a Setting like:
config.DefaultDictType = typeof(MyDict);
somewhere
There isn't a simple setting for this. Properties declared as IDictionary<TKey,TValue> are allocated as Dictionary<TKey, TValue> if the current value is null.
However, if you pre-allocate the custom dictionaries in the default constructors for your classes, Json.NET will use the pre-existing allocated dictionary rather than allocating a new one. (This is why JsonConverter.ReadJson has an existingValue argument.)
For instance:
public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
}
public class DictionaryContainer
{
public DictionaryContainer()
{
this.Values = new MyDictionary<string, string>();
}
public IDictionary<string, string> Values { get; set; }
}
public static class TestClass
{
public static void Test()
{
var container = new DictionaryContainer();
container.Values["one"] = "first";
container.Values["two"] = "second";
container.Values["three"] = "third";
Debug.Assert(container.Values.GetType() == typeof(MyDictionary<string, string>)); // No assert
var json = JsonConvert.SerializeObject(container, Formatting.Indented);
var container2 = JsonConvert.DeserializeObject<DictionaryContainer>(json);
Debug.Assert(container.Values.GetType() == container2.Values.GetType());// No assert
}
}
If this is impractical (because of, e.g., issues with legacy code), the easiest way to achieve what you want is probably with a single global converter that, when reading, allocates dictionaries for all properties defined to return type IDictionary<TKey,TValue> for any key and value:
public abstract class CustomDictionaryTypeReaderBase : JsonConverter
{
protected abstract Type CreateDictionaryType(Type tKey, Type tValue);
bool GetIDictionaryGenericParameters(Type objectType, out Type tKey, out Type tValue)
{
tKey = tValue = null;
if (!objectType.IsGenericType)
return false;
var genericType = objectType.GetGenericTypeDefinition();
if (genericType != typeof(IDictionary<,>))
return false;
var args = objectType.GetGenericArguments();
if (args.Length != 2)
tKey = tValue = null;
tKey = args[0];
tValue = args[1];
return true;
}
public override bool CanConvert(Type objectType)
{
Type tKey, tValue;
return GetIDictionaryGenericParameters(objectType, out tKey, out tValue);
}
public override bool CanWrite { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (existingValue != null)
{
serializer.Populate(reader, existingValue);
return existingValue;
}
else
{
Type tKey, tValue;
bool ok = GetIDictionaryGenericParameters(objectType, out tKey, out tValue);
if (!ok)
{
return serializer.Deserialize(reader, objectType);
}
else
{
var realType = CreateDictionaryType(tKey, tValue);
Debug.Assert(objectType.IsAssignableFrom(realType));
return serializer.Deserialize(reader, realType);
}
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public sealed class MyCustomDictionaryTypeReader : CustomDictionaryTypeReaderBase
{
protected override Type CreateDictionaryType(Type tKey, Type tValue)
{
var dictType = typeof(MyDictionary<,>).MakeGenericType(new[] { tKey, tValue });
return dictType;
}
}
And then use it like:
var settings = new JsonSerializerSettings();
settings.Converters = new[] { new MyCustomDictionaryTypeReader() };
var multiContainer2 = JsonConvert.DeserializeObject<MultipleDictionaryContainer>(json2, settings);
Another way to achieve what you wanted is by modifying the DefaultContractResolver, override its CreateDictionaryContract() method, and then set it as the serializer's default ContractResolver.
Assuming your custom dictionary is defined as:
public class CustomDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public string Custom { get { return "I'm Custom"; } }
}
You could implement the custom contract resolver as:
public class CustomDictionaryContractResolver : DefaultContractResolver
{
public CustomDictionaryContractResolver() : base(true) { }
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
// let the base class do the heavy lifting
var contract = base.CreateDictionaryContract(objectType);
// nothing todo if the created type is already our custom dictionary type
if (IsGenericDefinition(contract.CreatedType, typeof (CustomDictionary<,>)))
return contract;
if (IsGenericDefinition(contract.UnderlyingType, typeof(IDictionary<,>)) || (typeof(IDictionary).IsAssignableFrom(contract.UnderlyingType)))
{
contract.CreatedType = typeof(CustomDictionary<,>)
.MakeGenericType(contract.DictionaryKeyType ?? typeof(object), contract.DictionaryValueType ?? typeof(object));
// Set our object instantiation using the default constructor;
// You need to modify this, if your custom dictionary does not
// have a default constructor.
contract.DefaultCreator = () => Activator.CreateInstance(contract.CreatedType);
}
return contract;
}
static bool IsGenericDefinition(Type type, Type genericDefinition)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == genericDefinition;
}
}
And then use it like:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new CustomDictionaryContractResolver()
};
For example:
public class MyObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
public IDictionary<string, object> Properties { get; set; }
}
public static class TestClass
{
public static void Test()
{
const string json = #"{""FirstName"": ""John"",""LastName"": ""Smith"",""Properties"": {""Email"": ""john.smith#example.com"",""Level"": 42,""Admin"": true}}";
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new CustomDictionaryContractResolver()
};
var myObject = JsonConvert.DeserializeObject<MyObject>(json);
Debug.WriteLineIf(myObject.FirstName == "John", "FirstName is John");
Debug.WriteLineIf(myObject.LastName == "Smith", "LastName is Smith");
Debug.WriteLineIf(myObject.Properties != null, "Properties is not NULL");
Debug.WriteLineIf(myObject.Properties.Count == 3, "Properties has 3 items");
Debug.WriteLineIf(myObject.Properties.GetType() == typeof(CustomDictionary<string, object>), "Properties is CustomDictionary<,>");
var customDictionary = myObject.Properties as CustomDictionary<string, object>;
Debug.WriteLineIf(customDictionary != null, "Properties say " + customDictionary.Custom);
}
}
If you run the TestClass.Test() method, you should see the following in the Output:
FirstName is John
LastName is Smith
Properties is not NULL
Properties has 3 items
Properties is CustomDictionary
Properties say I'm Custom

deserializing json object with nested lists

I have an object that contains nested lists and a method to deserialize it from json using custom converters and .net's javascript serializer. Something like this:
public class MyObject{
int TheID { get; set; }
public List<MyNestedObject1> ListOfMyNestedObject1 { get; set; }
public List<MyNestedObject2> ListOfMyNestedObject2 { get; set; }
public MyObject ObjectFromJson(string TheObjectInJson) {
JavaScriptSerializer TheSerializer = new JavaScriptSerializer();
TheSerializer.RegisterConverters(new JavaScriptConverter[] {
new MyObjectConvert()
});
TheSerializer.RegisterConverters(new JavaScriptConverter[] {
new MyNestedObject1Convert()
});
TheSerializer.RegisterConverters(new JavaScriptConverter[] {
new MyNestedObject2Convert()
});
//if I comment out the registrations of the converters, it works
//but I need the converters of the nested objects to kick in
return TheSerializer.Deserialize<MyObject>(TheObjectInJson);
}
}
The json converters for the nested objects both look like this:
public class MyNestedObject1Convert : JavaScriptConverter {
public override IEnumerable<Type> SupportedTypes {
get { return new Type[] { typeof(MyNestedObject1Convert) };
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{ //deserialization logic
return MyNestedObject1;}
}
And the converter for MyObject looks like this:
public class MyObjectConvert : JavaScriptConverter {
public override IEnumerable<Type> SupportedTypes { get { return new Type[] { typeof(MyObjectConvert) }; }
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) {
int TheID;
MyObject TheObject = new MyObject();
int.TryParse(serializer.ConvertToType<string>(dictionary["TheID"]), out TheID))
TheObject.ID = TheID;
return TheObject;
}
}
Now the calling function that receives the json string and looks to return the c# object looks like this:
MyObject AMyObject = new MyObject();
MyObject TheMyObject = new MyObject();
TheMyObject = AMyObject.ObjectFromJson(JsonString);
When I run this code, the returned object contains TheID but the nested objects are null. I'm registering the converters in the object method but I'm guessing that's not the way to do it. If I remove the registration of the converters, the object DOES contain the nested objects, but then the converters don't kick in.
What do I need to change? Note: I'm not looking to use another library, just to make the native deserializer work.
Thanks for your suggestions.
Ok, so I got it to work. If you're looking to deserialize nested lists, this is how you do it.
First, don't register the converters in the MyObject ObjectFromJson method.
Second, it's in the custom converter of MyObject that you do the deserialization of the nested lists. Like this:
public class MyObjectConvert : JavaScriptConverter {
public override IEnumerable<Type> SupportedTypes { get { return new Type[] { typeof(MyObjectConvert) }; }
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) {
int TheID;
MyObject TheObject = new MyObject();
int.TryParse(serializer.ConvertToType<string>(dictionary["TheID"]), out TheID))
TheObject.ID = TheID;
if (dictionary.ContainsKey("ListOfMyNestedObject1"))
{
serializer.RegisterConverters(new JavaScriptConverter[] { new MyNestedObject1Convert() });
var TheList = serializer.ConvertToType<List<MyNestedObject1>>(dictionary["ListOfMyNestedObject1"]);
TheObject.ListOfMyNestedObject1 = TheList
}
return TheObject;
}
}
And voila: json deserialization of nested lists with .net's javascriptserializer using custom javascript converters.

Categories