majstor
majstor

Reputation: 419

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

Upvotes: 3

Views: 1354

Answers (1)

Stephen Kennedy
Stephen Kennedy

Reputation: 21548

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

Upvotes: 4

Related Questions