I've been designing web services for quite a while now but never had to expose a 'complicated' WCF service until recently. I was baffled at the apparent lack of "proper support" in WCF for abstract types. Sure - you can USE them - sure you can get them to 'work'... you just don't end up with what you WANT...
The first problem is that if you generate code from a wsdl with an abstract type you get vastly different code because it falls back to the xmlserializer and not the DataContractSerializer. This is obviously a bit less than desirable... I'd like to use the fancy new faster serializer please thank you... (and all that comes along with Service/DataContract)
on the flip side - if you start with code first and expose a properly attributed abstract wcf class as a web service the exposed wsdl does NOT contain the abstract="true" attribute making the "abstract class" technically concrete... This is not what I want of course...
I've got a workaround but it involves a crazy amount of 'hackery' where I create the wsdl/xsd contract first, remove any abstract="true" (oh - let's not mention that I can't use attributes in the xsd shall we) and then svcuitl the result... But now I'm left with a c# api that has a CONCRETE abstract class and I then need to go modify that to ADD the abstract keyword... This 'works' but it's a huge pita - and not easily 'scriptable'...
This is all just whacked! I'm hoping someone can explain to me precisely 'why' this is... I welcome answers that don't cite "solid" resources but I'm really waiting for the person to tell me - with proper documentation (like preferably from good ol Don Box himself) why exactly this is... Cause I just don't get it...
Thanks all - if anyone would like more details - please let me know!
UPDATED FOR ADDITION OF A SAMPLE REQUEST - starting with c#
[ServiceContract]
public interface IShapeTest
{
[OperationContract]
AbsShape EchoShape(AbsShape shape);
}
public class ShapeTestImpl : IShapeTest
{
public AbsShape EchoShape(AbsShape shape)
{
return shape;
}
}
[KnownType(typeof(Square))]
public abstract class AbsShape
{
[DataMember]
public int numSides;
}
public class Square : AbsShape
{
public Square() : base()
{
numSides = 4;//set the numSides to 'prove' it works
}
}
EXPECTED TYPE:
<xs:complexType name="AbsShape" abstract="true"> <!--NOTE abstract="true"-->
<xs:sequence>
<xs:element minOccurs="0" name="numSides" type="xs:int"/>
</xs:sequence>
</xs:complexType>
ACTUAL EMITTED TYPE:
<xs:complexType name="AbsShape"> <!--NOTE the lack of abstract="true"-->
<xs:sequence>
<xs:element minOccurs="0" name="numSides" type="xs:int"/>
</xs:sequence>
</xs:complexType>
Well it's because WCF doesn't pass objects, it passes messages. This isn't remoting, so the type end up with on the client is not the same type you have on the server - it's simply a holding class for various properties. Implementing "abstract="true" simply makes no sense. Messages are just data - how would the client know what concrete type to use, as you're not sharing classes, but simply a representation of the message.
"abstract" is an implementation detail. It has no place in a service contract. Naturally, as soon as you insist that your caller must be aware you are returning an abstract type, WCF must fall back on a serializer that can expose this fact: and you're back to being stuck with the XmlSerializer.
I suspect you're using abstract because that's the OO way to do things. But you're not doing OO, you're doing web services - SOA. There's a difference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With