Inherit from abstract class in WCF without exposing that class - c#

I have various classes which I want to expose as Complex Types in WCF, so I add [DataContract] and [DataMember] attributes as necessary on those types and properties.
However if I want to have them inherit from an abstract base class (for example Person inherits from abstract EntityBase), I get an error that the type "cannot inherit from a type that is not marked with DataContractAttribute or SerializableAttribute".
The problem is, if I add [DataContract] attribute to the base class, then that base class is exposed to the client via the WSDL. Not a huge deal I guess, but I would prefer my client doesn't know about my internal implementation.
If I add the [Serializable] attribute to the base class, then it seemed to work at first (it could be serialized but EntityBase was not referenced in the WSDL), but now if I add any properties to EntityBase then it will also complain that its properties are not serializable. (For example I add an ICollection then I get an error that RuleViolation is not serializable).
Unfortunately there seems to be no analogue to [IgnoreDataMember] for a [Serializable] type ([NonSerialized applies only to fields, not properties).
So basically I want to declare this base type but don't need any of its members to be serialized; is there any way to set this up in WCF so the client doesn't see this base type?

Did you try not marking your entities with [DataContract] and [DataMember] at all (so that default serialization is used) and instead marking base class properties with [IgnoreDataMember]?
You always have several choices and I'm afraid you will not like any of them.
Create a set of DTO objects and convert entities to DTO. This is generally a best practice if you want to hide your inner implementation.
Create a surrogate class (implement IDataContractSuroggate) for each entity so that you have control over serialization - I'm not sure if this avoids the problem.
Upgrade to .NET 4.0 and use EF with POCO classes (with no EntityBase as parent)
Best regards, Ladislav

I think you have to use the KnownType attribute.
For instance see WCF issues with KnownType for Dictionary
[EDIT] A more complete discussion of this problem and its solution can be found here:
WCF: Interfaces, Generics and ServiceKnownType

Related

Can't clone object. Serialization issue

I have a class generated by Linq2Sql:
public partial class BuyerOrder : INotifyPropertyChanging, INotifyPropertyChanged
I want to clone object of this class, like it's done in this post. For this purpose I define the partial class in not generated file, which I mark as serializable:
[Serializable]
public partial class BuyerOrder
But when I'm calling
formatter.Serialize(stream, source);
I'm getting an exception, saying that this class is not marked as serializable. What am I doing wrong?
If you want to serialize a LINQ-to-SQL type, then tell the code-gen to emit serializable data. You can do this in the DBML, or more simply in the designer - just set the serialization mode to unidirectional (this is the #Serialization attribute on the root <Database> element in the DBML).
This will generate attribute markers suitable for use with DataContractSerializer; LINQ-to-SQL is designed to be serializable with DataContractSerializer. It is not designed to be serializable with BinaryFormatter.
Every class derived from BuyerOrder must also be decorated as [Serializable], as well as all objects that the serializing instance holds a reference to (unless decorated as NonSerializable).
The exception should tell you the type that is missing the serializable attribute. If you can not or do not want to decorate all the classes you will need to get a little more creative.
-- The other possibility --
One option is to use the technique described in Implementing a generic deep-clone for C# objects. Since this can be done entirely in memory and without a binary formatter it will perform many times faster than serialization based cloning.
The source code is located at http://csharptest.net/browse/src/Library/Cloning
It only takes two lines of code:
using (ObjectCloner cloner = new SerializerClone())
fooCopy = cloner.Clone(foo);

Abstract Class Inheritance & Data Contracts

I have an abstract class BaseClass with two attributes I want to share with class ClassA : BaseClass and class ClassB : BaseClass. However, I want both ClassA and ClassB to be marked with DataContractAttribute in a way that the members inherited from BaseClass are also exposed in the contract. However, I don't want BaseClass itself to be exposed as a data contract. Is this possible in WCF (.NET 3.5)?
No, AFAIK that is not possible. Even if you new the properties to add data-member markers it'll still complain:
Type 'BaseClass' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.

serializable to derived classes

Is there an easy way to enforce a derived class must be serialiable?
Suppose I define a interface that needs the derived classes to be serializable. According to this post, I cannot just specify the serializable attribute in the interface, because derived classes don't need to respect that.
I believe I could have the interface inherit from the ISerializable interface, but does that mean that the derived class couldn't use the attribute to specify serialization (as opposed to actually implementing the methods for ISerializable)?
We cannot use [Serializable] as
gives error with an interface.
We may use [Serializable] attribute
with base class but even then this
attribute is not inherited. This does
not seem possible.
Have a look a this link as well.
Enforcing serializable from an
interface without forcing classes to
custom serialize in C#.

Custom Serialization of base class properties

I have a class that is implementing the ISerializable interface for custom serialization. This works great for the properties in this class but the class is a derived class. The problem i'm running into is that the base class properties aren't serialized for me. The base class has the serializable attribue but doesnt implement ISerializable. Is there a way to serialize the base class properties without having to add all of them manually in the derived class's ISerializable .GetObjectData method?
From MSDN
As I mentioned, the ISerializable interface is extremely powerful since it allows a type to take complete control over how instances of the type get serialized and deserialized. This power comes at a cost; the type is now responsible for serializing all of its base type's fields as well. Serializing the base type's fields is easy if the base type also implements the ISerializable interface—you just call the base type's GetObjectData method. Someday you may find yourself defining a type that needs to take control of its serialization, but whose base type does not implement the ISerializable interface. In this case, your class must manually serialize the base type's fields.

If Base class is marked Serializable are all child classes marked too?

I have a whole list of entity classes which I need to make Serializable (due to storing session state in SQL, but that's another story).
I have added the attribute [Serializable] and all seems to be fine.
All of my entity classes extend from the same base class.
If I mark the base class as Serializable, does this mean all children are marked as Serializable too?
Thanks
No, attribute is not inherited.
When you extend the class, it's possible to add features that might not be serializable by nature therefore .NET framework cannot assume for you that everything what extends serializable base class is also serializable.
That's why you must explicitly state [Serializable] attribute on every class individually.
Nope, each one will have to be marked as [Serializable] specifically.
Also if you intend to serialize an object to XML which is of a derived type as though it is the base type you'll also need a [XmlInclude] attribute.
EG:
[Serializable]
public class BaseClass : ParentClass
{
}
[Serializable]
[XmlInclude(typeof(BaseClass))]
public class ParentClass
{
}
(Binary serialization, like what is used for sessions, do not need this)

Categories

Resources