Search code examples
c#.netjsonserializationjavascriptserializer

How to serialize a property which is decorated with the [ScriptIgnore] attribute?


I'm trying to serialize an object which has some properties with the [ScriptIgnore] attribute. However, I sometimes want the JavaScriptSerializer to not ignore properties with that attribute. Are there any possibilities to serialize the whole object in spite of the [ScriptIgnore] attribute?

Here's some sample code:

public static string ConvertToJson(this object objectToConvert)
{
    var serializer = new JavaScriptSerializer();
    return serializer.Serialize(objectToConvert);
}

public static void ConvertFromJson(this object objectToConvert, string jsonString)
{
    var serializer = new JavaScriptSerializer();
    object dummy = serializer.Deserialize(jsonString, objectToConvert.GetType());

    foreach(PropertyInfo property in objectToConvert.GetType().GetProperties())
        if(property.CanRead && property.CanWrite && property.GetCustomAttribute<ScriptIgnoreAttribute>() == null)
            property.SetValue(objectToConvert, property.GetValue(dummy));
}

Solution

  • You can control the entire serialization process by coding and supplying a JavaScriptConverter object.

    For testing let us use this simple class with a single property which is decorated with the ScriptIgnore attribute:

    public class TestObject
    {
        [ScriptIgnore]
        public string TestString { get; set; }
    }
    

    ...and then serialize an instance of it:

    var serializer = new JavaScriptSerializer();
    Console.WriteLine(serializer.Serialize(new TestObject { TestString = "test" }));
    

    The property is of course ignored. Output:

    {}

    Now we'll define a JavaScriptConverter. The relevant part here is our implementation of Serialize():

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var testObject = obj as TestObject;
    
        if (testObject != null)
        {
            // Create the representation. This is a simplified example.
            Dictionary<string, object> result = new Dictionary<string, object>();
            result.Add("TestString", testObject.TestString);        
            return result;
        }
    
        return new Dictionary<string, object>();
    }
    

    We simply add the ignored property to the output. That's it!

    You'd supply the converter when you want to serialize everything; and without the converter, by default, the annotated properties would be ignored.

    Usage:

    serializer.RegisterConverters(new List<JavaScriptConverter> { new TestObjectConverter() });
    

    Output:

    {"TestString":"test"}


    Full code dump:

    void Main()
    {
        var serializer = new JavaScriptSerializer();
        Console.WriteLine(serializer.Serialize(new TestObject { TestString = "test" })); // prints: {}
        serializer.RegisterConverters(new List<JavaScriptConverter> { new TestObjectConverter() });
        Console.WriteLine(serializer.Serialize(new TestObject { TestString = "test" })); // prints: {"TestString":"test"}
    }
    
    public class TestObject
    {
        [ScriptIgnore]
        public string TestString { get; set; }
    }
    
    public class TestObjectConverter : JavaScriptConverter
    {
        private static readonly IEnumerable<Type> supportedTypes = new List<Type> { typeof(TestObject) };
    
        public override IEnumerable<Type> SupportedTypes => supportedTypes;
    
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var testObject = obj as TestObject;
    
            if (testObject != null)
            {
                // Create the representation. This is a simplified example. You can use reflection or hard code all properties to be written or do it any other way you like - up to you.
                Dictionary<string, object> result = new Dictionary<string, object>();
                result.Add("TestString", testObject.TestString);        
                return result;
            }
    
            return new Dictionary<string, object>();
        }
    }