Abstract classes in client lib, and concrete class in shared lib - wcf

How do I solve the serialization problem with abstract class defined in a shared client library, and concrete implementation in a server side library.
Interface in shared client library :
[ServiceContract(SessionMode=SessionMode.Required)]
[ServiceKnownType(typeof(SharedClient.Shape))]
public interface IMyInterface
{
void UploadDrawing(Drawing dr);
}
Concreate Drawing class in shared client library :
[DataContract]
[KnownType(typeof(SharedClient.Shape))]
public class Drawing
{
public Shape s;
}
Abstract class in shared client library :
[DataContract]
abstract public class Shape
{
[DataMember]
public abstract string Name;
}
Concrete class implementation in separate library which references the client library :
[DataContract]
public class Cirle : ClientLibrary.Shape
{
public override string Name { get; set; }
}
I keep getting the exception message:
There was an error while trying to serialize parameter
http://tempuri.org/:Drawing. The InnerException message was 'Type
'Circle' with data contract name
'Circle:http://schemas.datacontract.org/2004/07/' is not expected.
Consider using a DataContractResolver or add any types not known
statically to the list of known types - for example, by using the
KnownTypeAttribute attribute or by adding them to the list of known
types passed to DataContractSerializer.'. Please see InnerException
for more details.

KnownType works in other way. If you want to use KnownType attribute you must use it on the base class to define its child:
[DataContract]
[KnownType(typeof(Circle))]
abstract public class Shape
{
[DataMember]
public abstract string Name;
}
That will not be too much helpful in your case. Try to put ServiceKnownType with concrete class on your interface:
[ServiceContract(SessionMode=SessionMode.Required)]
[ServiceKnownType(typeof(Circle))]
public interface IMyInterface
{
void UploadDrawing(Drawing dr);
}
You doesn't have to define Shape as ServiceKnownType - it is already known because it is used in Drawing but WCF yet doesn't know the Circle type.

Related

KnownType for MessageContract in WCF

I am using Stream object inside my wcf Contracts so forced to use MessageContract instead of DataContract.
[MessageContract]
public class Document
{
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileData;
}
[MessageContract]
public class A : Document
{
[MessageBodyMember]
public string input;
}
[MessageContract]
public class B : Document
{
[MessageBodyMember]
public string someProp;
}
[ServiceContract]
public interface ISomeService
{
[OperationContract]
Document SomeMethod(Document file);
}
I want the consumer of this service to create object of either A or B and call the service with it. On the service side, I can type cast it to proper object then perform some action.
Problem is I cannot specified KnownType with MessageContract and inherited contracts cannot be exposed to client until they are used in service or declared with KnownType.
I tried google it but couldn't find anything related to KnownType with MessageContract.
As suggested in comment... i updated my message contract with KnownType but they are still not exposed to client through service reference...
[MessageContract]
[KnownType(typeof(FileSystemStoredDocument))]
[KnownType(typeof(FileBoundStoredDocument))]
[KnownType(typeof(SharepointStoredDocument))]
public class Document : DocumentInfo, IDisposable
{
}
Can any one help me what's wrong here?
Note: ALL KnownType are inherited from Document
Message contracts describe exactly how the message should look like. They do support inheritance, but you must specify the exact message contract you're using in a specific operation.
If you check the body parts of the message:
ContractDescription.GetContract(typeof(ISomeService)).Operations[0].Messages[0].Body.Parts
You'll see exactly one part - a Stream object. That's in contrast to data contracts, where the body contains a part of the type Object. So you see why KnownType wouldn't work here.
(The ContractDescription class is used, among other things, to generate WSDL. See the WsdlExporter class.)
What you can do is create a hierarchy of data contracts that would be contained in the message contract, e.g.
[MessageContract]
public class Document
{
[MessageHeader]
public DocumentProperties Properties;
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileData;
}
[DataContract]
[KnownType(typeof(A))]
[KnownType(typeof(B))]
public abstract class DocumentProperties { }
[DataContract]
public class A : DocumentProperties
{
[DataMember]
public string input;
}
[DataContract]
public class B : DocumentProperties
{
[DataMember]
public string someProp;
}
Note that you you cannot have more than one body member if you want to pass a Stream, so the rest of the properties must be in headers.

Protobuf type inheritance with WCF

We have trouble with the protobuf-net type inheritance.
We have a base class like this:
[DataContract, ProtoContract]
public abstract class BaseClass : IBase
{
protected IBase()
{
RequestUID = Guid.NewGuid();
}
[DataMember(Order = 8000), ProtoMember(8000)]
public Guid ID { get; set; }
[DataMember(Order = 8001), ProtoMember(8001)]
public string User { get; set; }
}
And classes which inherits from BaseClass.
[DataContract, ProtoContract]
public class ConcreteClass : BaseClass
{
[DataMember(Order = 4), ProtoMember(4)]
public int? WorkItemId { get; set; }
}
(In future we are going to use only ProtoMember and ProtoContract.)
When the client and server starts we do following in both environments:
RuntimeTypeModel.Default[typeof(BaseClass)].AddSubType(50, typeof(ConcreteClass));
Now when we pass an instance of ConcreteClass to a WCF service operation we get exceptions:
BaseClass does not provide a public constructor. (Wrong type chosen for deserialization)
Or if we provide a public constructor for BaseClass it tries to cast the BaseClass object to ConcreteClass on the server. (Again wrong type)
And under some special circumstances (we don't know exactly when this happens) Protobuf tries to deserialize from OtherConcreteClass to ConcreteClass.
What are we doing wrong? The WCF behavior is register correctly. We had no problems with simple classes (no inheritance).
Is there and documentation how two configure the inheritance properly for WCF scenarios?
Thanks

serialize an interface wcf

I have an interface, called IDeviceConfig, as follows:
[KnownType(typeof(Device))]
[KnownType(typeof(DeviceGroup))]
[DataContract()]
public interface IDeviceConfig
{
[DataMember()]
string Name { get; set; }
[DataMember()]
List<Property> Properties { get; set; }
ActionResult PerformAction(string ActionId);
}
The interface will be implemented by two classes, as follows:
public class Device : IDeviceConfig
{
...
}
public class DeviceGroup : IDeviceConfig
{
...
}
In my WCF service, I need to return a list of IDeviceConfigs; when I decorate the interface with KnownType, Visual studio complains saying that Attribute 'KnownType' is not valid on this declaration type.
Can someone please explain how to return a list of IDeviceconfigs?
If you look at the definition of KnownTypeAttribute, you cannot apply to Interfaces.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)]
public sealed class KnownTypeAttribute : Attribute
"Known types can be associated only with classes and structures, not interfaces." from here:
http://msdn.microsoft.com/en-us/library/ms730167.aspx

Serializing parent class fields using ServiceStack Redis/TextSerializer

I have two classes
public class ClassOne {
public Guid Id { get; set; }
}
public class ClassTwo : ClassOne {
}
When I send an instance of ClassTwo to Redis (using ServiceStack via its TypeSerializer) the superclass properties (e.g. Id) does not Serialize because it's on the parent class.
Is there a way to get this working?
Only abstract classes, interfaces or late-bound objects emit the necessary __type info required for inheritance to work. So if you must use inheritance (which is a bad idea in DTOs) change ClassOne to abstract.

Error while running WCF service library

I have built a WCF service library, I have added reference to few 3rd party dll's. This is my interface
[ServiceContract]
public interface IService1
{
[OperationContract]
3rdpartyreturntype GetObj(System.Windows.Controls.Control txtcontrol);
}
// Use a data contract as illustrated in the sample below to add composite types to service operations
[DataContract]
public class nclass
{
[DataMember]
public System.Windows.Controls.Control txtcontrol
{
get { return txtcontrol; }
set { txtcontrol = value; }
}
[DataMember]
public 3rdpartyreturntype nobj
{
get { return vuiobj; }
set { vuiobj = value; }
}
[DataMember]
public System.Windows.Input.TouchDevice tchdev
{
get { return tchdev; }
set { tchdev = value; }
}
}
and I have implemented the above interface. When I run the service I get the below error, can anyone help me out?
type 'System.Windows.Input.TouchDevice' cannot be serialized. Consider
marking it with the DataContractAttribute attribute, and marking all
of its members you want serialized with the DataMemberAttribute
attribute.
if you want a complex type like a class to be serialized you have to declare each of its members as data member and class as datacontract.
In this case touch device is the complex type(class) so you need to mark all of its members as datamembers and class as datacontract.
but as i can see from type that it belongs to system.windows.input the class may not be serialized. hence you cannot use this as a data member.
If you are using only a set of members belonging to touchDevice class, you can create your own class which will map only the set of touchdevice members which can be serialized. and decorate this new class with datacontract and datamember attributes.
It would appear that the type "System.Windows.Input.TouchDevice" is itself not marked as serializable or a DataContract.
Instead of trying to pass the TouchDevice and the Control directly like that, maybe you can just pass the properties you care about. I'm guessing in the case of the TextControl you just care about the Text value. And for the TouchDevice, maybe the source and target control name?