Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serialize only simple types using Json.Net

I am not sure why anybody has not asked about this question yet but I am trying to serialize only simple types of a given object using IContractResolver interface. I don't really want to mark each property using ShouldSerialize method or JsonDataAttribute or anything like this.

What I have done so far shown as following on LinqPad

Some sample classes to serialize

class Customer
{
    public List<Order> Orders {get;set;}
    public int CustomerId {get;set;}
    public string[] Addresses {get;set;}
}

class Order
{
    public int OrderId{get;set;}
    public string Name {get;set;}
    public int Amount {get;set;}
    public Order PreviousOrder {get;set;}
}

An extension method to serialize all the objects

static class ExtensionMethods
{
    public static string JsonSerialize (this object obj)
    {
        var settings = new JsonSerializerSettings();
        settings.ContractResolver = new MyContractResolver();
        settings.DefaultValueHandling = DefaultValueHandling.Ignore;
        settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        return JsonConvert.SerializeObject(obj,settings);
    }
}

My Custom Contract Resolver Class

public class MyContractResolver: DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member,memberSerialization);
        property.ShouldSerialize = instance => instance.GetType().IsPrimitive || instance.GetType() == typeof(string) || instance.GetType() == typeof(decimal);
        return property;
    }
}

and Main method:

void Main()
{
    var customer = new Customer
                {
                    Orders = ProduceSomeOrders(),
                    Addresses = new string[] {"9450 S. Small Street Dr.","9521 Flintstone Dr. S"},
                    CustomerId = 1
                };

    var jsonOrder = customer.JsonSerialize();
    jsonOrder.Dump();
}

I only want to serialize sample types such as int,double,string,decimal,bool etc. but not arrays, collections, custom objects etc. and it will only navigate the first level, not 2nd or more levels down. I really wonder why there is not any simple method which does this in Json.Net.

This is the output when I run this code: (an empty json)

{ }

I've realized one thing when I run this code, the first member parameter passed into the CreateProperty method is the main object itself which in this case is Customer instance. But since this will work for all sort of types I just don't want to say instance.GetType() == typeof(Customer) or something like this in the method. The expected output in this case is only CustomerId in this case.

Do you know any graceful way to handle my problem?

like image 259
Tarik Avatar asked Apr 10 '13 15:04

Tarik


People also ask

What can be serialized in JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object). If you serialize this result it will generate a text with the structure and the record returned.

Can JSON serialize a list?

Json.NET has excellent support for serializing and deserializing collections of objects. To serialize a collection - a generic list, array, dictionary, or your own custom collection - simply call the serializer with the object you want to get JSON for.

Does JSON serialize data?

Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). Serialization is the process of converting the state of an object, that is, the values of its properties, into a form that can be stored or transmitted.

What is JsonConvert DeserializeObject C#?

DeserializeObject<T>(String,JsonConverter[]) Deserializes the JSON to the specified . NET type using a collection of JsonConverter. DeserializeObject(String, JsonSerializerSettings)


2 Answers

Instead of overriding CreateProperty method, I am overriding GetSerializableObjects method as it gives all the possible members I will get:

public class MyContractResolver: DefaultContractResolver
{
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        var members = base.GetSerializableMembers(objectType);
        var filteredMembers = new List<MemberInfo>();
        members.ForEach(m=>{
            if(m.MemberType == MemberTypes.Property)
            {
                PropertyInfo info = (PropertyInfo) m;
                var type = info.PropertyType;
                if(type.IsPrimitive || type == typeof(string) || type == typeof(decimal))
                {
                    filteredMembers.Add(m);
                }
            }
        });
        return filteredMembers;
    }
}
like image 44
Tarik Avatar answered Oct 05 '22 06:10

Tarik


By changing the method below I got the result: {"CustomerId":1}. Is this what you were looking for?

public class MyContractResolver:DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
    var property = base.CreateProperty(member,memberSerialization);

    var propertyType = property.PropertyType;
    if(propertyType == typeof(int) 
        || propertyType == typeof(string)){
        property.ShouldSerialize = instance => true;
    }
    else
    {
        property.ShouldSerialize = instance => false;
    }
    return property;
}
}
like image 130
TalonMcShay Avatar answered Oct 05 '22 05:10

TalonMcShay