2

The class that I need gets serialized as a web service response body.

The problem is, the properties from the base class get serialized along with it, and I can't have that for this service.

I need to block those properties from being serialized on only this subclass. So I tried hiding the properties using new but the base class properties are still being serialized (i.e. "Hello, world" is in the resulting http response body):

public class MyBaseClass
{
    public string MyProperty { get { return "Hello, world"; } }
}

public class MyChildClass : MyBaseClass
{
    [XmlIgnore]
    [JsonIgnore]
    public new string MyProperty { get; set; }
}

this gets returned via something like this:

return myHttpRequestMessage.CreateResponse(myStatusCode, myChildClassInstance);

So two questions

  • What up with that? Why isn't it honoring the child class with its decorations?
  • Is there another way to achieve what I'm trying to achieve (which is preventing the decorated properties from being serialized?

I know it's a total kludge, but until I have the time to fix the deeper issue (which is the operation that's forcing this inheritance), this is what I have to work with.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
Sinaesthetic
  • 11,426
  • 28
  • 107
  • 176
  • How do you initialize the instance of the child class? – Robert Moskal Apr 15 '15 at 21:47
  • `[Serializable]` declaration on your class? – Jacob Roberts Apr 15 '15 at 21:47
  • Your test case reproduces for Json.Net, but not for `DataContractJsonSerializer`, which serializes the child property in preference to the parent. Does that help? – dbc Apr 15 '15 at 22:23
  • Assuming you are using Json.NET, this is possibly related: https://stackoverflow.com/questions/27887787/jsonpropertyattribute-ignored-on-private-property-in-derived-class – dbc Apr 15 '15 at 22:30
  • I'm using the default serializer which I think uses json.net for json and datacontractserializer for xml. Need to support both. I'm testing json first, I hadn't tried xml specifically. @dbc is that what you're saying? That if it were xml, it'd be fine? @robert It is is just `var childInstance = new ChildClass()`. Nothing special. – Sinaesthetic Apr 15 '15 at 23:13

2 Answers2

0

JSON

If you are using JSON.NET (which is a default JSON serializer in Web.API), then you will probably need to use custom ContractResolver. Answers for this question has a good examples of creating such type of class. In the following examples I will use IgnorableSerializerContractResolver from one of the answers.

Now you can register it in Global.asax:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new IgnorableSerializerContractResolver()
    .Ignore<MyBaseClass>(x => x.MyProperty);

If you already using some contract resolver (for example CamelCasePropertyNamesContractResolver) then you will need to combine them somehow.

XML

I don't know what type (DataContractSerializer or XmlSerializer) of XML serialization are you using, but as I know, DataContractSerializer doesn't allow to exclude properties in runtime. You will need to use XmlSerializer. You can set custom serializers per type:

var xmlOver = new XmlAttributeOverrides();
var xmlAttr = new XmlAttributes { XmlIgnore = true };
xmlOver.Add(typeof(MyBaseClass), "MyProperty", xmlAttr);

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.SetSerializer<MyChildClass>(new XmlSerializer(typeof(MyChildClass), xmlOver));

Siple way

If you have access to your MyBaseClass and allowed to do some changes, then you can solve your problem using Data attributes:

[DataContract]
public class MyBaseClass
{
    public string MyProperty { get; set; }
}

[DataContract]
public class MyChildClass : MyBaseClass
{
    [DataMember]
    public string MyProperty2 { get; set; }
}

In this case you can use default serializers (JSON.NET for JSON and DataContractSerializer for XML) and it will be solved for you automatically. Please note that you must add DataContract to MyBaseClass, or otherwise XML serialization will fail.

Community
  • 1
  • 1
Aleksandr Ivanov
  • 2,778
  • 5
  • 27
  • 35
0

In order to ignore a property from the base class you could override this property in the derived class and decorate it with JsonIgnoreAttribute:

public class MyBaseClass
{
    public virtual string MyProperty { get { return "Hello, world"; } }
}

public class MyChildClass : MyBaseClass
{
    [JsonIgnore]
    public override string MyProperty { get; }
}

You get an empty json object serializing it:

Debug.Assert(Newtonsoft.Json.JsonConvert.SerializeObject(new MyChildClass()) == "{}");
Andriy Tolstoy
  • 5,690
  • 2
  • 31
  • 30