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.
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.
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()) == "{}");
Related
I have data that is best described as "onion-like" in that each outer layer builds on the one below it. Below you will see a vastly simplified version (mine is several layers deeper but exhibits the same behavior at each level).
[CollectionDataContract]
public abstract class AbstractTestGroup : ObservableCollection<AbstractTest>
{
[DataMember]
public abstract string Name { get; set; }
}
[CollectionDataContract]
[KnownType(typeof(Test))]
public class TestGroup : AbstractTestGroup
{
public override string Name
{
get { return "TestGroupName"; }
set { }
}
[DataMember]
public string Why { get { return "Why"; } set { } }
}
[DataContract]
public abstract class AbstractTest
{
[DataMember]
public abstract string SayHello { get; set; }
}
[DataContract]
public class Test : AbstractTest
{
//Concrete class - members in this class get serialized
[DataMember]
public string Month { get { return "June"; } set { } }
public override string SayHello { get { return "HELLO"; } set { } }
}
I create an instance of TestGroup and add Test objects to it using the .Add that comes with the ObservableCollection.
When I serialize and de-serialize this structure I get the following
<TestGroup xmlns="http://schemas.datacontract.org/2004/07/WpfApplication2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AbstractTest i:type="Test">
<SayHello>HELLO</SayHello>
<Month>June</Month>
</AbstractTest>
</TestGroup>
The output has left off the DataMembers in TestGroup. As I get deeper in my onion, no DataMembers that are higher are included (even from the abstract classes). I have tried adding [KnownType(typeof(TestGroup))] to both TestGroup and AbstractTestGroup without success.
The question: Why am I not able to serialize the DataMember Why in the TestGroup class?
Follow up question: Is there an alternative way to serialize and de-serialize a structure of this shape? I am planning on using the output locally to "load" the configuration the user specifies. I would prefer to not have to specify my own Serialization scheme if I can avoid it.
For those interested here is how I am generating the class, serializing, and de-serializing it.
TestGroup tg = new TestGroup();
tg.Add(new Test());
DataContractSerializer ser = new DataContractSerializer(typeof(TestGroup));
MemoryStream memoryStream = new MemoryStream();
ser.WriteObject(memoryStream, tg);
memoryStream.Seek(0, SeekOrigin.Begin);
string str;
using (StreamReader sr = new StreamReader(memoryStream))
str = sr.ReadToEnd();
Edit: For what it's worth I tried changing to using Serializable instead and have the same issue.
The reason why the property Why is not serialized is because TestGroup is a collection. And DataContract treats collections specially. The end result is that only the data in the collection is stored and none of the properties are stored.
Lists are stored in a way that any other list could read them in. The only differentiation is between collections and dictionaries. A good reference is http://msdn.microsoft.com/en-us/library/aa347850%28v=vs.110%29.aspx
UPDATE: I've seen some things online that may help you. In particular, change the abstract class attribute declarations to the following:
[DataContract]
[KnownTypes(typeof(Test))]
public abstract class AbstractTest { /* ... */ }
You could have a look at the documentation at MSDN on the KnownTypesAttribute. Apparently, there's also a constructor overload that takes a string that resolves to a method name that would be found via reflection and would be called by the DataContractSerializer to determine the known types for a base class (if you had multiple known types and/or possibly needed to dynamically return known types that may not be known at compile time). There's also web.config XML configurations for setting up known types.
UPDATE: I noticed that the KnownTypesAttribute attribute seems to be misused in the code examples in the OP. So, I wanted to elaborate the above with the full code that should work.
[CollectionDataContract]
[KnownTypes(typeof(TestGroup))] // Need to tell DCS that this class's metadata will be included with members from this abstract base class.
public abstract class AbstractTestGroup : ObservableCollection<AbstractTest>
{
[DataMember]
public abstract string Name { get; set; }
}
[CollectionDataContract]
//[KnownTypes(typeof(Test))] -- You don't need this here....
public class TestGroup : AbstractTestGroup
{
[DataMember] // Even though this is a derived class, you still need to tell DCS to serialize this overridden property when serializing this type
public override string Name
{
get { return "TestGroupName"; }
set { }
}
[DataMember]
public string Why { get { return "Why"; } set { } }
}
[DataContract]
[KnownTypes(typeof(Test))] // Again, you need to inform DCS
public abstract class AbstractTest
{
[DataMember]
public abstract string SayHello { get; set; }
}
[DataContract]
public class Test : AbstractTest
{
//Concrete class - members in this class get serialized
[DataMember]
public string Month { get { return "June"; } set { } }
[DataMember] // Even though this is a derived class, you still need to tell DCS to serialize this overridden property when serializing this type
public override string SayHello { get { return "HELLO"; } set { } }
}
See the comments next to the KnownTypesAttribute attributes in the example above.
UPDATE: Added the DataMemberAttribute attribute to the derived class' overridden properties.
UPDATE: OK, there may be an added dimension to this that is causing the behavior you're referencing. Do you have an interface or a class that is decorated with the ServiceContractAttribute attribute, where the service contains a method which returns one of these abstract types above? If so, then you also need to decorate said interface or class method that returns the abstract type with the ServiceKnownTypesAttribute attribute. A quick and dirty example follows:
[ServiceContract]
//[ServiceKnownTypes(typeof(TestGroup))] -- You could also place the attribute here...not sure what the difference is, though.
public interface ITestGroupService
{
[OperationContract]
[ServiceKnownTypes(typeof(TestGroup))]
AbstractTestGroup GetTestGroup();
}
HTH.
I frequently find myself implementing this sort of class:
public class Something
{
public string Serialize()
{
// serialization code goes here
}
public static Something Deserialize(string str)
{
// deserialization code goes here
}
}
I would like to enforce this across all classes of this type by making the above class implement an interface that looks something like this:
public interface ISerializationItem<T>
{
string Serialize();
T Deserialize(string str);
}
Alas, this is not possible, because the the interface can't cover the static method, and the method needs to be static so that it does not depend on any instance of the class.
Update: Typically, I would deserialize as shown below; the static method effectively serves to construct an instance of the class, so I don't want to already have an instance at hand to be able to do this:
var str = "Whatever";
var something = Something.Deserialize(str);
Is there a proper way to enforce this constraint?
Keep your "data" classes simple/pure of any logic and then write the serialization processes in a separate class. This will make maintaining the data classes and serializer easier. If each class needs customization then create attribute classes and decorate your data classes with these attributes.
Here is some pseudo example...
public class Employee
{
public int Id { get; set;}
[ForceSpecialHandling]
public string Name { get; set; }
}
public class CustomSerializer
{
public T Serialize<T>(string data)
{
// Write the serialization code here.
}
}
// This can be whatever attribute name you want.
// You can then check if the property or class has this attribute using reflection.
public class ForceSpecialHandlingAttribute : Attribute
{
}
My project gets a lot of JSON strings via UDP, each string describing some list of objects.
I could'nt write a function that get a some list, and make Derialization to this list.
The problem is that I can not make Derialization without knowing the class name of the objects that make up the list.
I tried to give each department ID field .. But here, too, I could not do Derialization for specific field, because where the department name is not known.
Does anyone have a solution?
Yes, the JSON problem.
I would go the way of encapsulation.
Firstly I would create the wrapper:
public class JSONObjectWrapper
{
public string ObjectType;
public string ObjectInJSON;
[DoNotSerialize] // sorry do not remember the attribute to exclude it from serialization
public object ObjectData;
}
During serialization you will explicitly serialize ObjectData into ObjectInJSON. And then send the serialized JSONOBjectWrapper.
On the incoming side you always know it is JSONObjectWrapper. Deserialize it - by this you get the JSON with the object and object type. Find this object type, create it using some factory and then deserialize it from OBjectInJSON into ObjectData.
The procedure above will work only if you may do the wrapping on the transmitting side. Otherwise, you are screwed :-)
Make all your entities get implemented from Base class:
public abstract class BaseEntity
{
public EntityTypeEnum EntityType {get;set;}
}
public enum EntityTypeEnum
{
EntityOne,
EntityTwo,
EntityThree
}
Now you can deserialize at the begining your entity from JSON to BaseEntity, look what kind of entity you get end then deserialize to the type which you get.
JsonSerializer js = new JsonSerializer();
var baseEntity = js.Deserialize<BaseEntity>()
switch(baseEntity.EntityType)
{
case EntityOne:
var result= js.Deserialize<EntityOne>();
//DoSomeThing
break;
case EntityTwo:
var result= js.Deserialize<EntityTwo>();
//DoSomeThing
break;
}
EDIT for Zoka
If you want to implement anything else by your entity you can do like this:
public class AnythingElse : BaseEntity
{
//...
}
public class EntityFour : AnythingElse
{
//....
}
EDIT №2 for Zoka
If you need your DTOs to be implemented from any other 3rd party library class just do like this:
public abstract class BaseEntity : AnyOther3rdPartyLibraryClass
{
public EntityTypeEnum EntityType {get;set;}
}
public class EntityFive : BaseEntity
{
...
}
I am using a DataContractJsonSerializer and have an issue with the DataMember Name.
I made a base class and several derived classes. I need the derived classes because I have different json strings. I want to deserialize the json strings and therefore need different names for the datamembers. I try to change the DataMember name as in the following example:
Baseclass:
[DataContract]
public abstract class BaseClass
{
[DataMember]
public virtual string FirstMethod { get; protected set; }
}
Derived class:
[DataContract]
[KnownType(typeof(BaseAccess))]
public class DerivedClass
{
[DataMember(Name="first_method")]
public virtual string FirstMethod { get; protected set; }
}
Problem is that when I use a derived class the serialization seems to ignore the given DataMember name. So when I deserialize with the type DerivedClass the serialization seems to take place with the name "FirstMethod" (of the base class) instead of "first_method" (of the derived class). Is it possible to use the DataMember name of the derived class (which is different for several derived classes in my situation).
Another question. I found examples with KnownType added on the base class and added on the derived class. Seems logic to me to do it on the derived class (espcially for inheritance concerns). What is correct?
I had this same issue. I was using VB.NET and I had to Shadow (or Overload) the property to get WCF to respect the DataMember property in my derived class. In C# you should be able to use the new operator.
public class DerivedClass
{
[DataMember(Name = "first_method")]
new public string FirstMethod { get; protected set; }
}
The trick is to specify EmitDefaultValue = false for the base class's virtual data member, and in its implementation in the derived class return default value so the data member is not serialized. In the derived class define another data member with the required name.
[DataContract(Name = "baseclass", Namespace = "")]
[KnownType(typeof(DerivedClass))]
public class BaseClass
{
[DataMember(Name = "attributes", EmitDefaultValue = false)]
public virtual SomeType Fields { get; set; }
}
[DataContract(Name = "derivedclass", Namespace = "")]
public class DerivedClass : BaseClass
{
public override SomeType Fields
{
get { return null; }
}
[DataMember(Name = "fields")]
public SomeType DerivedFields
{
get { return base.Fields; }
}
}
I'm trying to find a way to change the serialization behavior of a property.
Lets say I have a situation like this:
[Serializable]
public class Record
{
public DateTime LastUpdated {get; set; }
// other useful properties ...
}
public class EmployeeRecord : Record
{
public string EmployeeName {get; set; }
// other useful properties ...
}
Now I want to serialize EmployeeRecord. I don't want the LastUpdated property from the Record class to be serialized. (I do want LastUpdated to be serialized when I serialize Record, though).
First I tried hiding the LastUpdated property by using the new keyword and then adding the XmlIgnore attribute:
public class EmployeeRecord : Record
{
public string EmployeeName {get; set; }
[XmlIgnore]
public new DateTime LastUpdated {get; set; }
// other useful properties ...
}
But that didn't work. Then I tried making the base LastUpdated virtual and overriding it, keeping the attribute:
[Serializable]
public class Record
{
public virtual DateTime LastUpdated {get; set; }
// other useful properties ...
}
public class EmployeeRecord : Record
{
public string EmployeeName {get; set; }
[XmlIgnore]
public override DateTime LastUpdated {get; set; }
// other useful properties ...
}
This didn't work either. In both attempts the LastUpdated ignored the XmlIgnore attribute and happily went about its business of serializing.
Is there a way to make what I'm trying to do happen?
First, the [Serializable] attr has nothing to do with the XmlSerializer. That is a red herring. [Serializable] is meaningful to System.Runtime.Serialization, while the XmlSerializer lives in System.Xml.Serialization. If you are decorating your class with [Serializable] and your members with [XmlIgnore] then you are probably confusing yourself or other readers of your code.
XmlSerialization in .NET is very flexible. Depending on how the serialization is being done, directly by you or indirectly, let's say by the web services runtime - you have different ways to control things.
One option is to use the propertyNameSpecified pattern to turn ON or OFF the property in XML Serialization. Suppose you have this code:
public class TypeA
{
public DateTime LastModified;
[XmlIgnore]
public bool LastModifiedSpecified;
}
Then, if LastModifiedSpecified is false in an instance, the LastModified field will not be serialized for that instance. In the constructor for your type, you can set LastModifiedSpecified to always be true in the base type, and always false in the derived type. The actual boolean - LastModifiedSpecified - never gets serialized because it is marked XmlIgnore.
This little trick is documented here.
Your other option is to use XmlAttributeOverrides, which is a way of dynamically providing the set of XML serialization attributes (like XmlElementAttribute, XmlIgnoreAttribute, XmlRootAttribute, and so on...) - dynamically providing those attributes to the serializer at runtime. The XmlSerializer, instead of inspecting the type itself for those attributes, will just walk through the list of override attributes provided to its constructor.
var overrides = new XmlAttributeOverrides();
// ....fill the overrides here....
// create a new instance of the serializer specifying overrides
var s1 = new XmlSerializer(typeof(Foo), overrides);
// serialize as normal, here.
This is illustrated in more detail here.
In your case, you would provide an XmlIgnoreAttribute as an override, but only when serializing the derived type. (or whatever) This works only when you directly instantiate the XmlSerializer - it won't work when serialization is done implicitly by the runtime, as with web services.
Cheers!
The best I can think of...
[Serializable]
public class Record
{
public DateTime LastUpdated {get; set; }
public virtual bool ShouldSerializeLastUpdated() {return true;}
// other useful properties ...
}
public class EmployeeRecord : Record
{
public string EmployeeName {get; set; }
public override bool ShouldSerializeLastUpdated() {return false;}
// other useful properties ...
}
Basically, there are a few patterns that XmlSerializer respects; public bool ShouldSerialize*(), and public bool *Specified {get;set;} (note you should mark *Specified with [XmlIgnore] too...).
Not very elegant, I'll grant; but XmlSerializer only looks at public members, so you can't even hide them (short of [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]).