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; }
}
}
Related
I would like to use an abstract base class (call it AbstractBaseClassA) which holds only one property (virtual - Property1) of type List of another abstract base class (Call it AbstractBaseClassB).
I have another class which should inherit from AbstractBaseClassA (call it superClassA) and implement the property but as a List of class (type) that inherit from the AbstractBaseClassB (call it superClassB).
I would like the property of superClassA - Property1 override the property of AbstractBaseClassA - I can't use the override it because it is a List of elements that aren't from the same class (but from inherited class) and as so - it doesn't implement the abstract class, and when I use the "new" keyword - I get an error message claiming:
"There was an error reflecting property Member Property1: superClassA.Property1 of type System.Collections.Generic.List'1 hides base class member AbstractBaseClassA.Property1 of type System.Collections.Generic.List'1".
The error occures when I try to serialize xml to superClassA object (I removed the xml Attributes).
What should I do in order to make it work ?
This is my code:
public abstract class AbstractBaseClassA
{
[XmlIgnore]
public virtual List<AbstractBaseClassB> Property1 {get; set;}
}
public Abstract class AbstractBaseClassB
{
public string simpleProperty1111 {get; set;}
/*constructors*/
public AbstractBaseClassB(){}
public AbstractBaseClassB(string prop1)
{
simpleProperty1111 = prop1;
}
}
public class superClassB : AbstractBaseClassB
{
public string simplePropety2222 {get; set;};
/*constructors*/
public superClassB() : base(){}
public superClassB(string prop22222, string prop11111) : base(prop11111)
{
simplePropety2222 = prop22222;
}
}
public class superClassA : AbstractBaseClassA
{
public new List<superClassB> Property1 {get; set;}
}
SOLVED : I've used the "virtual" (in abstract class) and the "new" keyword (in the inherited class) and I've changed the XmlAttribute over the virtual property with [XmlIgnore]
SOLVED: code in the question is updated: I've used the "virtual" (in abstract class) and the "new" keyword (in the inherited class) and I've changed the XmlAttribute over the virtual property with [XmlIgnore]
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.
Is it possible to prevent using abstract classes as property type?
I have a abstract base class being inherited in an abstract class with generic type, which in turn is inherited in classes with defined types. Is it possible to "lock down" the abstract class with generic type, so it's not possible to use it as a property in other classes?
Here's an approximation of my situation. I want to prevent the possibility of creating properties like doubleFoo2. The Foo<T> should only be able to be inherited in other classes, and not be able to be used as a type directly.
Since I'm validating PropertyType of properties and their base types, this lead to me making a mistake it took me a while to find. Here's a test of the code: https://dotnetfiddle.net/OMHmGv
public abstract class FooBase
{
// Various generic properties and methods
}
public abstract class Foo<T> : FooBase
{
public Type ValueType { get { return typeof(T); } }
public abstract T Value { get; set; }
}
public class DoubleFoo : Foo<double>
{
public override double Value { get; set; }
}
public class FooHandler
{
public DoubleFoo doubleFoo1 { get; set; }
public Foo<double> doubleFoo2 { get; set; }
}
Not only it's impossible, it goes against one of the three basic principles of object oriented programming - and I'm talking, of course, about polymorphism.
Giving up polymorphism is giving up object oriented programming altogether.
The point is that a reference of a type can actually refer to an instance of any type deriving from the reference type.
Polymorphism is what makes the following code line is perfectly valid (even though not very useful):
object s = "the type is actually a string but the reference is of type object";
Edit: Like what #Zohar Peled said, it defeats the purpose of polymorphism, restricting usage based on namespace or assembly is your only way.
If the DoubleFoo and its child classes are created in a seperate assembly, you may use the
internal
modifier instead of
public
for both FooBase and Foo classes to prevent other assemblies from access them.
If you have to use this DoubleFoo in the same assembly, you can try putting the base classes in the different namespace to hide the base implementation classes.
An example would be:
Inside FooOfT.cs
namespace FooTester.DoubleFoo.Foo
{
public abstract class FooBase
{
// Various generic properties and methods
}
public abstract class Foo<T> : FooBase
{
public Type ValueType { get { return typeof(T); } }
public abstract T Value { get; set; }
}
}
Inside DoubleFoo.cs
using FooTester.DoubleFoo.Foo
namespace FooTester.DoubleFoo
{
public class DoubleFoo : Foo<double>
{
public override double Value { get; set; }
}
}
inside FooHandler.cs
using FooTester.DoubleFoo
namespace FooTester
{
public class FooHandler
{
public DoubleFoo doubleFoo1 { get; set; }
// public Foo<double> doubleFoo2 { get; set; } Cannot access Foo<T> class
}
}
I have two classes, RichString and RequiredRichString. In RequiredRichString, I'm re-implementing the Value property with the 'new' keyword. If I reflect the attributes on Value on RequiredRichString, I only get Required, but after testing posting markup multiple times, AllowHtml is still taking effect.
public class RichString
{
[AllowHtml]
public string Value { get; set; }
}
public class RequiredRichString : RichString
{
[Required]
new public string Value { get; set; }
}
In short: Why does ASP.NET still acknowledge the AllowHtml attribute when I re-implement the Value property with new?
If you have the flag set:
[AttributeUsage(Inherited=true)]
Then the attribute will be inherited.
But you can subclass the Attribute to your needs, ie MyAttribute(Enabled = true) in the base class and MyAttribute(Enabled = false) in the new implementation. For instance...
[AttributeUsage(Inherited=true, AllowMultiple=true, Inherited=true)]
public class MyAttribute : Attribute
{
public bool Enabled { get; set; }
public MyAttribute() { }
public void SomethingTheAttributeDoes()
{
if (this.Enabled) this._DoIt)();
}
}
public class MyObject
{
[MyAttribute(Enabled = true)]
public double SizeOfIndexFinger { get; set; }
}
public class ExtendedObject : MyObject
{
[MyAttribute(Enabled = false)]
public new double SizeOfIndexFinger { get; set; }
}
Note this answer: How to hide an inherited property in a class without modifying the inherited class (base class)? - it seems maybe you can achieve what you want by using method overriding rather than hiding.
I can understand why you would think otherwise for a new property, but my understanding is that new is about providing a new implementation, often in the form of a new storage mechanism (a new backing field for instance) rather than changing the visible interface of the subclass. Inherited=true is a promise that subclasses will inherit the Attribute. It makes sense or at least it could be argued that only a superseding Attribute should be able to break this promise.
I have seen this kind of definition in a library I'm using. I got crazy about the where TObjectType: CSObject. It is obvious that It seems I can use the same time in the constraint because it works and compiles but what does this really mean?
public class CSList<TObjectType>: CSList, IList<TObjectType>, IList
where TObjectType: CSObject<TObjectType>
It means that the TObjectType here must inherit from CSList<TObjectType>.
Usually you use this construct to get typed methods and properties on the base class that adjust to the actual derived classes you intend to use.
To declare such a derived class:
public class SomeDerivedClass : CSList<SomeDerivedClass>
Example:
public class Base<T>
{
public T[] Values { get; set; }
}
public TestCollection : Base<TestCollection>
{
// here, Values inherited from Base will be:
// public TestCollection[] Values { get; set; }
}
public OtherCollection : Base<OtherCollection>
{
// here, Values inherited from Base will be:
// public OtherCollection[] Values { get; set; }
}