« Retire the Tenets? | Main | Dependency Injection - Good or Bad Practice? »

19.08.07

The Four Tenets and XML Messaging with WCF

Don Box has responded to my post on Harry Pierson’s discussion about retiring the four tenets. I would like to respond to some of  his statements:

Harmut states “WCF Contracts are still CLR-Classes, not Schema or Contract.” This isn’t quite right. The in-memory representation for WCF contracts is a DOM-ish tree that can be cons’ed up using any number of techniques, not just writing C# interfaces with [ServiceContract] (go look at Sys.SvcModel.Description.ContractDescription if you care to spelunk). ContractDesc is neither CLR reflection data nor WSDL – rather it’s the optimized in-memory rep used throughout our runtime. FWIW, we’re actively investing in other ways to write ContractDescs down (honestly I’m not a big fan of CLR interfaces or WSDL – please God tell me we can do better).

I know about WCF’s representation of Service Contracts. What I meant was that concerning the Service Design WCF Contracts are still CLR classes annotated with WCF attributes. As a service developer or designer I don’t care about the internal representation, I’m using the “API” representation. In the WCF case this is - at least in the Service Model - a CLR interface or class.

Before continuing I want to express my deep respect for the design of WCF, especially its channel model layer and XML messaging framework.  The service model layer serves as a mapping between the XML (WSDL, XSD) world and the CLR world. In some cases this is the right approach, in the case of service-oriented principles it’s not. WCF serves two main purposes: a) consolidating the former .NET APIs  for distributed computing and b) providing a web service stack for implementing services according to service-oriented tenets (here we go again).

Doesn’t WCF live up to the second purpose, then? Well, no and yes. As Ben Kloosterman points out in the comments to Don’s post “the biggest problems is people have no experience with SOA so they fall back on remote object tecniques but using an SOA tool like WCF”. I would change this to “SOA tool like the WCF service model”. That’s the first and maybe most important argument against the service model (when implementing SOA services!):

  1. Developers and designers tend to fall back to traditional remote object techniques.
  2. The “schema and contract” mentioned in the four tenets are reduced to generated artifacts, which aren’t even part of your code basis. A contract has to be designed, not generated!
  3. X-O-Mapping will never satisfy all your needs. WCF Contracts and XML Serialization won’t either.
  4. Loose coupling is what all tenets (to some extend) are all about. The need to (re)generate proxies when a provider or consumer changes even in the smallest degree is not what I would call loosely coupled. This is a weak argument, which should be examined in greater detail. Granted.
  5. Mark Seeman states in the comments to Don’s post: “It’s easy to understand”. I would say that C# interfaces that are cluttered with C# attributes are as easy to understand as XSD schemas or even more difficult.

Let’s have a look at this example of a data contract taken from “Designing Service Contracts with WCF:

[DataContract(Namespace = "http://schemas.thatindigogirl.com/2005/12/LinkItems", Name = "LinkItem")]
    public class LinkItem {
        [DataMember(Name = "Id", IsRequired = false, Order = 0)]
        private long id;
        [DataMember(Name = "Title", IsRequired = true, Order = 1)]
        private string title;
        [DataMember(Name = "Description", IsRequired = true, Order = 2)]
        private string description;
        [DataMember(Name = "DateStart", IsRequired = true, Order = 3)]
        private DateTime dateStart;
        [DataMember(Name = "DateEnd", IsRequired = false, Order = 4)]
        private Nullable<DateTime> dateEnd;
        [DataMember(Name = "Url", IsRequired = false, Order = 5)]
        private string url;
        [DataMember(Name = "LinkType", IsRequired = false, Order = 6)]
        private string linkType;
    }

The corresponding XSD schema looks like this:

<xs:schema elementFormDefault="qualified" 
           targetNamespace="http://schemas.thatindigogirl.com/2005/12/LinkItems" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:tns="http://schemas.thatindigogirl.com/2005/12/LinkItems">
  <xs:complexType name="LinkItem">
    <xs:sequence>
      <xs:element minOccurs="0" name="Id" type="xs:long"/>
      <xs:element name="Title" nillable="true" type="xs:string"/>
      <xs:element name="Description" nillable="true" type="xs:string"/>
      <xs:element name="DateStart" type="xs:dateTime"/>
      <xs:element minOccurs="0" name="DateEnd" nillable="true" type="xs:dateTime"/>
      <xs:element minOccurs="0" name="Url" nillable="true" type="xs:string"/>
      <xs:element minOccurs="0" name="LinkType" nillable="true" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

The namespace declarations within the schema element are a little bit confusing when you’re not accustomed to XML. But all the rest isn’t really more difficult than the C# interface, is it?  In my opinion every service designer and developer has to have a profound understanding of XML. Hey, you are developing SOAP Web Services. You should have a basic understanding of your published contracts/interfaces, don’t you?? When you do have a good understanding of XML, XSD isn’t that difficult anymore (regarding interoperability you should stick to simple type definitions).

But what do you gain from incorporating XSD (and WSDL) as first-class citizens into your implementations?

  1. A good understanding of your published interfaces. This is a must!
  2. Very expressive contracts. For instance if you include a zip code in your type definitions, its contents should be of type string and limited to the zip code format of your country. This restriction could easily be integrated in your human- and machine-readable contract by the XSD concept of “inheritance by restriction”. A concept unknown to the CLR (type system). When using WCF contracts these restrictions have to be written down in a separate API docs that are likely to be ignored by the majority of developers. Contracts cannot be ignored, they are validated by your service (at least they should be - see below).
  3. We could implement a very forgiving validation thereby enhancing the loose coupling of our services. We’ll come to that in a moment. 
  4. Flexibility.

The sad thing about WCF is, that it doesn’t provide real schema validation. It provides XML Serialization, which partly does the same. Luckily there is a nice way of adding schema validation to WCF. The good thing is that WCF supports XML messaging out-of-the box.

Don asks me (and others) to “sketch out a concrete example of what they would rather write assuming a “traditional” imperative programming language (static or dynamically typed)”. Here is my answer:

1. Model your data types with XSD and your contracts with WSDL. It is no fun to write a complete WSDL on your own, but there are ways of simplifying this task. You might use a modeling tool (such as the one to be published with v3 of the Web Service Software Factory) or you might model your messages in your schema and generate the WSDL with a template based code generation approach.  

2. Register and publish your contract (WSDL & XSD) in your service registry/repository. There isn’t any real (or state of the art) repository/registry solution provided by Microsoft. But there are other solutions, which might be used. After all we are living in a service world, which is independent of vendors and platforms …

3. Take the “untyped services” approach of WCF:

[OperationContract(Action = "CreateLink")]
Message CreateLinkItem(Message aLink);

The Message objects represents the SOAP envelope and provides access to its headers and the complete XML contents. Although this approach is called “untyped”, your contracts are strictly typed. So “untyped” only refers to the generic CLR interface. Type-checking is provided by:

4. Validate incoming messages via the custom Behavior/Inspector mentioned above or even better via Schematron. This approach is beyond the scope of this post. I’ll cover this topic in one of my future posts. There is no Schematron implementation for .NET (save an abandoned project)? No problem, just revert to the reference implementation :-).

Schematron allows your services to be very forgiving concerning changes in your consumer’s logic. Your service might expect a purchase order. This purchase order has to conform to a certain structure. If your consumer extends this structure, you’re not supposed to break! After all, everything you request is still provided. As already mentioned above, I’ll provide an example for this approach in one of my future posts. 

5. Access the payload of the message by using XPath expressions. You might also use the XmlDictionaryReader or LINQ to XML (or LINQ to XSD).

So, I don’t want an alternative to WCF. I only want to use what’s already there. It is either incorporated into WCF already or can be added via WCF extension points. In my opinion XML messaging with WCF is the best approach for developing services that adhere to the four tenets.

Posted by Hartmut Wilms at 19.08.07 19:18