Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

When using XSD.EXE to generate classes from an XML Schema, it generates xxxSpecified members of any primitives of a given object:

<xs:complexType name ="Foo">
    <xs:all>
      <xs:element name ="Count" type = "xs:integer"/>
    </xs:all>
</xs:complexType>

....generates:

public class Foo
{
    public int Count { get; set; }
    public bool CountSpecified { get; set; }
}

It appears the latest version of JSON.NET can automatically set these properties when deserializing.

string request = "{ Count : 10 }";
var object = JsonConvert.Deserialize<Foo>(request)
Assert.IsTrue(object.Count = 10); // Yup
Assert.IsTrue(object.CountSpecified == true);  //Also yup - JSON.NET works!

However, when going the other way, the xxxSpecified properties are included in the JSON output, which is incorrect, as it is not part of the schema.

string request = JsonConvert.Serialize(object); 
//{  
//   Count: 10, 
//   CountSpecified : true    <-- This is incorrect - should not be output 
//}

Is there any setting I am missing that controls whether to output the xxxSpecified attributes? How can I suppress it?

(Note: This is a permutation of a question answered here:

JSON.NET, XmlSerializer and "Specified" property

...but it involves creating extension classes, which is not possible for me, as there are hundreds of classes in the schema and I can't change the inheritance hierarchy. So the answer won't work. Looking for another way.)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
1.1k views
Welcome To Ask or Share your Answers For Others

1 Answer

You can create your own contract resolver to filter out xxxSpecified properties:

public class SkipSpecifiedContractResolver : DefaultContractResolver
{
    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
    static SkipSpecifiedContractResolver instance;

    static SkipSpecifiedContractResolver() { instance = new SkipSpecifiedContractResolver(); }

    public static SkipSpecifiedContractResolver Instance { get { return instance; } }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        ILookup<string, JsonProperty> lookup = null;
        foreach (var property in properties)
        {
            if (property.GetIsSpecified != null && property.SetIsSpecified != null)
            {
                var name = property.UnderlyingName + "Specified";
                lookup = lookup ?? properties.ToLookup(p => p.UnderlyingName);
                var specified = lookup[name]
                    // Possibly also check for [XmlIgnore] being applied.  While not shown in the question, xsd.exe will always
                    // apply [XmlIgnore] to xxxSpecified tracking properties.
                    //.Where(p => p.AttributeProvider.GetAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute),true).Any())
                    .SingleOrDefault();
                if (specified != null)
                    specified.Ignored = true;
            }
        }
        return properties;
    }
}

Then use it like:

var settings = new JsonSerializerSettings { ContractResolver = SkipSpecifiedContractResolver.Instance };
var object = JsonConvert.DeserializeObject<Foo>(request, settings);

If you want to do this always, you can set the contract resolver in the global JsonConvert.DefaultSettings:

JsonConvert.DefaultSettings = (() =>
{
    return new JsonSerializerSettings { ContractResolver = SkipSpecifiedContractResolver.Instance };
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...