tags:

views:

631

answers:

3

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>
+1  A: 

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.

blowdart
thanks for your response and i've seen this sort of answer on the internet but I don't believe it's "correct". I say this because even though it's passing messages those messages can still be polymorphic. if polymorphism was an issue I would expect that the DataContractSerializer wouldn't accept ANY object that derived from any other (well maybe ecluding object).The really odd thing is that if you hand craft your OWN wsdl that uses has 'abstract=true' - WCF has no issues and it works just fine... the PROBLEM is that the emitted type is inconsistent... imho
dovholuk
Messages really aren't polymorphic (unless your method accepts and returns a single type, Message)Sure an object which has a message contract applied do it can be polymorphic but it's life ends at the boundary of the service. So yes, you can get the abstract=true attribute for a complex type, but then how does the client know what concrete type is supposed to be used, unless you're getting into sharing implementation libraries, something SOA is supposed to separate us from.
blowdart
The client knows what type to be used by the xsi:type that is supplied in the xml... the same way the XmlSerializer does it... The only crazy part of this for me is that the XmlSerializer will handle this properly, the DataContractSerializer will also deserialize the xml properly but the DataContractSerializer just won't expose the type as abstract to start... I find it odd...
dovholuk
+1  A: 

"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.

John Saunders
thanks for your comment... my question - similar to the one i commented below - is why would WCF support ANY kind of polymorphic behavior then? side question - how does one do a 'choice' with WCF DataContractSerializer... It seems that the 'answer' is "you can't"... and i think that is 'wrong' - no?
dovholuk
No, the question is why are you trying to be explicit about your use of XML in data contracts. Recall that WCF does binary, JSON, Atom, etc, in addition to XML. xs:choice is an implementation dependency you should steer away from. Just keep your contracts to the semantics, and away from specifics of implementation.
John Saunders
let me try again. I hear where you're coming from so let me ask the question like this... "how can i specify a data contract that allows me to send an Apple data structure or an Orange data structure"? I didn't explicitly reference xs:choice because I didn't want to add confusion but now it's time do do so... Using schema I can do this in 1 of 3 ways.a.) "xsd polymorphism" (cleaner OO code - easier to maintain imo)b.) xs:choice (clearer xml - generally uglier OO code - xsd harder to maintain)c.) substitution groups ("close enough" to be the same as choice)so how do i do that with WCF?
dovholuk
Ok, that's a lot more clear. I don't have the details in front of me, but you _do_ want to use [KnownTypes].
John Saunders
yes I do want to use KnownTypes - I *have* to. [btw. "KnownTypes" is another pet peeve of mine with the .NET "service" stack - but that's not relevant to THIS discussion ;) ] The real question is that if I expose an abstract c# class it 'becomes' a concrete class in the wsdl - and this is 'wrong'... I'm merely trying to convey to the consumer "pick one of these things but not the parent" (hence the abs. type) yet when it's exposes as concrete - there's nothing 'telling' the consumer that the parent is NOT valid - in fact they should believe that it *IS* valid. thx for cont. the conversation.
dovholuk
+2  A: 

Since nobody has convinced me I will answer my own question with "WCF is schizophrenic"...

dovholuk