Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set Json.NET ContractSerializer for a certain specific type instead of globally?

I want to set a contract serializer just for certain types in my ASP.NET Web API application. I can set the settings globally in the App_Start/FormatterConfig.cs like this:

public static void RegisterGlobalFormatters(MediaTypeFormatterCollection formatters)
{
    jsonSerializerSettings.ContractResolver = new CriteriaContractResolver(new List<string>(new string[]{"mdData", "name", "label"})); 

...

but how can I just apply this to one or more specific class types?

The reason I want to do this is because I need to be able to set what fields should be serialized at runtime based on configuration or parameters to the web service similar to these examples:

Using JSON.net, how do I prevent serializing properties of a derived class, when used in a base class context?

http://json.codeplex.com/discussions/347610

like image 513
Rn222 Avatar asked Sep 19 '12 19:09

Rn222


2 Answers

You have a few options:

  • Create a custom type that is handled by a custom formatter. This custom type could specify (in some manner) what fields need to be serialized (and that information then fed into a Json serializer)
  • Look at per controller configuration (see here) to try and setup the formatter as requried
like image 63
Chris Avatar answered Sep 28 '22 02:09

Chris


I ended up using a JsonConverter that only writes the parameters that are specified in the "properties" list. It's more low level than a ContractResolver or a formatter, but I don't think it's possible to configure either one for a specific type.

public class ResourceConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Resource));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        List<string> properties = new List<string>(new string[] { "Name", "Label" });

        writer.WriteStartObject();
        foreach (MemberInfo mi in value.GetType().GetMembers(BindingFlags.GetField | BindingFlags.Instance | BindingFlags.Public) )
        {
            PropertyInfo p = mi as PropertyInfo;

            if (p != null && p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0 && properties.Contains(p.Name))
            {
                writer.WritePropertyName(p.Name);
                serializer.Serialize(writer, p.GetValue(value, new object[] { }));
            }
        }
        writer.WriteEndObject();
    }
}

This can be applied to a class using the attribute:

[JsonConverter(typeof(ResourceConverter))]

This seems like a hack though, I think I should use the contract resolver to get the list of properties to serialize instead of using reflection directly, but I'm not sure how.

like image 37
Rn222 Avatar answered Sep 28 '22 01:09

Rn222