How to deserialize a different interface implementation with wcf
Following situation:
Our software works with business objects, at the moment they are sent with wcf from the server to the client.
[Serializable]
public class SomeValueBO
{
public DateTime Timestamp{ get; set; }
}
They are packed in request/response messages.
[DataContract]
public class Response
{
[DataMember]
public List<SomeValueBO> Values { get; set; }
}
The Problem:
We would like to send DTO's to the client instead of the business object's. I heard, that it is possible to retrieve at the client an instance of a different type than was sent on the server.
Example:
public interface ISomeValue
{
DateTime Timestamp { get; set; }
}
[Serializable]
public class SomeValueBO : ISomeValue
{
public DateTime Timestamp { get; set; }
}
[DataContract]
public class SomeValueDTO : ISomeValue
{
[DataMember]
public DateTime Timestamp { get; set; }
}
The response would look like this:
[DataContract]
public class Response
{
[DataMember]
public List<ISomeValue> Values { get; set; }
}
On the server:
public class ServiceClass : IService
{
public Response HandleRequest(Request request)
{
Response response = new Response();
response.Values.Add(new SomeValueBO());
return response;
}
}
开发者_运维百科
On The client:
Response response = serviceProxy.HandleRequest(request);
ISomeValue value = response.Values[0];
value is SomeValueDTO
I tried it with declaring only the known type of the DTO object and with Data Contract Equivalence, but WCF still keep deserializing the item as a BO instance.
I have to add, that both ways have to work, Sending the BO and retrieving it as a BO and sending the BO and retrieving a DTO, but of course with different requests.
So my question is, is this possible and if yes, what am I doing wrong?
Thanks for help, Enyra
Edit: I also found out, that we are using the NetDataSerializer, could that be the problem that it does not work?
Even if you weren't using NetDataContractSerializer
(comment), the fact that SomeValueBO
isn't declared as a data-contract means that it will mainly be acting as a field-serializer. Which is a pain in particular because automatically-implemented properties are a royal pain re field serializers - they become insanely brittle.
I would declare as a contract:
[DataContract]
public class SomeValueBO
{
[DataMember]
public DateTime Timestamp{ get; set; }
}
and switch to DataContractSerializer
, but note that this is a breaking change - you would have to update all clients and servers at the same time. You would then be able to have alternative implementations as long as they shared the full contract signature.
Re the current use of NetDataContractSerializer
- if this is for performance, there are alternatives - there are contract based binary serializers that are faster (CPU) and smaller (bandwidth) than NetDataContractSerializer
: Performance Tests of Serializations used by WCF Bindings
From MSDN:
The NetDataContractSerializer differs from the DataContractSerializer in one important way: the NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can be used only if both the serializing and deserializing ends share the same CLR types.
That's why it's not working at present.
If you use the DataContractSerializer
instead, the client and the service only need to agree on the serialized XML representation of the object state, not on the exact CLR runtime type. You'll need to attribute both sides' types with DataContractAttribute
in order to get the XML namespace associated with the serialized representation the same on both sides. And obviously the data contracts will have to be equivalent in terms of the serialized structure.
That said, what you are trying to do should be workable with the DataContractSerializer
. As for whether it's the best way to go - like all design decisions "it depends".
精彩评论