views:

768

answers:

1

I am having a little trouble understanding ServiceKnownType in WCF.

Taken from this blog, the following code does not work:

[DataContract(Namespace = “http://mycompany.com/”)]
public class Shape{…}

[DataContract(Namespace = “http://mycompany.com/”)]
public class Circle : Shape {…}

[ServiceContract]
public interface IMyServer
{
    [OperationContract]
    bool AddShape(Shape shape);
}

.

IMyServer client = new ChannelFactory<IMyServer>(binding, endPoint).CreateChannel();

client.AddShape(new Circle());

The reason it doesn't work is because you are trying to add a circle, but the servicecontract only allows a Shape. You are supposed to do something with knowntypes, but I am a bit confused about how that works.

Since that code is in the service, why doesn't it know automatically that a Circle is derived from Shape? Additionally, what does ServiceKnownType actually do?

When ServiceKnownType is put below the DataContract, apparently that makes it work. I am guessing it says hey, this particular object type called Shape can also be a Circle. I am having trouble understanding why it would do it this way around, because if you add a new type like Square you are going to have to add to the Shape class a ServiceKnownType for it. Wouldn't it make sense if it cannot infer it, to put the KnownType onto the Square rather than the Shape? So the Square says hey, I am a Shape, and you don't have to fiddle with the Shape class? If your Shape class is built into a library and you want to create your own dervied shape like DiamondShape, you can't add it to the Shape class because you don't have access to the source code.

+1  A: 

The problem is that WCF does not go into all assemblies and tries to find all possibly sub-types of Shape. It also does not transmit the type information (assembly, fully qualified type name) with the XML document.

So, while it would be not a problem to generate a tag "Circle" on the outgoing XML, the incoming deserializater would not know what to do with this.

The KnownType "hack" is like a registry of known types that has to be implemented by both sides. It is explicit. With this registry, the deserializer knows that "Circle" deserializes to type X, without any chance of ambiquity and without having to parse all available or reachable assemblies for derived types.

Remember, Square does not say "I am a shape", it comes as a XML tag and from that you do not easily and automatically know which .NET class to use.

TomTom
Doesn't it just have to examine the DataContracts for that service though? There are only two in that example and it probably cached them anyway.
SLC
No, because the data contract does not say which subclasses are actually valid for that possible call - or which exist. data contract will just say "ok, this is a shape in this property" and not "which subclasses of share are coming here".
TomTom