2

My goal is to serialize properties that don't have any attributes and properties which have a specific custom attribute.

For the following class:

public class Msg
{
    public long Id { get; set; }

    [CustomAttributeA]
    public string Text { get; set; }

    [CustomAttributeB]
    public string Status { get; set; }
}

When I call a method Serialize(object, CustomAttributeA), I want to have the following output:

{
    "Id" : someId,
    "Text" : "some text"
}

And when I call Serialize(object, CustomAttributeB), I want to have following:

{
    "Id" : someId,
    "Status" : "some status"
}

I have read that it's possible to achieve this by creating a custom ContractResolver, but in this case must I create two separate contract resolvers?

1 Answer 1

5

You do not need two separate resolvers to achieve your goal. Just make the custom ContractResolver generic, where the type parameter represents the attribute you are looking for when serializing.

For example:

public class CustomResolver<T> : DefaultContractResolver where T : Attribute
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);

        foreach (JsonProperty prop in list)
        {
            PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
            if (pi != null)
            {
                // if the property has any attribute other than 
                // the specific one we are seeking, don't serialize it
                if (pi.GetCustomAttributes().Any() &&
                    pi.GetCustomAttribute<T>() == null)
                {
                    prop.ShouldSerialize = obj => false;
                }
            }
        }

        return list;
    }
}

Then, you can make a helper method to create the resolver and serialize your object:

public static string Serialize<T>(object obj) where T : Attribute
{
    JsonSerializerSettings settings = new JsonSerializerSettings
    {
        ContractResolver = new CustomResolver<T>(),
        Formatting = Formatting.Indented
    };
    return JsonConvert.SerializeObject(obj, settings);
}

When you want to serialize, call the helper like this:

string json = Serialize<CustomAttributeA>(msg);

Demo fiddle: https://dotnetfiddle.net/bRHbLy

Sign up to request clarification or add additional context in comments.

2 Comments

You could also make this generic - IMO a little neater Serialize<CustomTypeA>(obj) and Serialize<CustomTypeB>(obj);
Great answer BTW!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.