- Loosely coupled design pattern
- Declaratively annotation and control using a custom attribute
- Implicitly annotation using standard C# XML Comments
- Configuration using the service behavior extension
- Wsdl documentation from wcf service and operation contracts
- DataContract annotation
- MessageContract annotation
- POCO (Plain old C# objects) annotation (only for .netFx 3.5 SP1)
The wsdl 1.1 and xml schema include an option, where each element (component) can be annotated. The annotation is not a part of the service metadata. It is data about the data, to inform the service consumer in the human readable style about the metadata. For this purpose, the annotation can have any text representation style, for instance: html tags. Annotations do not participate in the validation process. For interoperability reason, the annotation component is not recommended to use as an additional exchange pattern or context between the service and its consumer.
The following picture is a screen snippet from the WSDL 1.1 spec:
As you can see in the above picture, there are lines such as 5, 8, 14, 19, etc. for wsdl component documentation and the spec said:
WSDL uses the optional wsdl:document element as a container for human readable documentation. The content of the element is arbitrary text and elements ("mixed" in XSD). The documentation element is allowed inside any WSDL language element.
The current release of the .NetFX 3.5 SP1 still doesn't have a built-in feature for annotating a wsdl document for any of its component. On the other hand, the WCF has a strong extensibility parading for plugging-in a custom annotator to describe your service metadata, as you will see more details later in this article.
Now, the questions are coming. Why and what do I need to annotate in the wsdl document? How much do I do it, etc.?
Well, there is no unique answer and guidelines for that. This article shows implementation of one example of this guideline, where the service contract is divided into two parts, such as partitioned wsdl documentations and xml schema annotation for object contract.
1. Service Contract Documentation in the WSDL Metadata
For documenting Service and Operation Contract in the WCF Service we can use C# Xml Comments and custom attribute such as
DocumentationAttribute. The following picture shows an example of this annotation:
The documentation of the
ServiceContract decorated by custom attribute and comment lines is mapped into the
<wsdl:service .../> components like it is shown in the following picture:
The documentation of the
OperationContract decorated by custom attribute and comment lines is mapped into the
<wsdl:operation .../> components like it is shown in the following picture:
As you can see, there are only two wsdl components for mapping documentation from the WCF Service. That's the feature which is supported by this article.
The second part of the WCF Service metadata annotation is related to the object and its serializable elements. In the above example, we have one object in the
OperationContract such as
MyMessageContract. Let's look at how it can be annotated.
2. Object annotation in the Xml Schema Metadata
In this case, similarly to previous one, we have C# Xml Comment lines and custom attribute such as
AnnotationAttribute. The major difference between these two cases is a target of the annotation. In the first case, described earlier, the target is the wsdl documentation section located in the separate service metadata section. In the second one, which is always related to the objects, the target is the XML Schema in the MetadataSection. Note, the number of sections in the metadata container is not limited and basically is depended on the service contract complexity.
Ok, let's continue with the following picture, where the
MessageContract object is shown.
As the above code snippet shows, there are standard C# Xml Comment lines and additional custom attributes for annotation in the class. Note, the custom
AnnotationAttribute is an optional attribute to the C# XML Comment lines. We can use this attribute for lightweight annotation only.
The following picture shows a snippet from the annotated XML Schema located in the metadata section:
As you can see in the above snippet, the
MessageBodyMember is a complex type. In this example, this object is serialized by
DataContractSerializer which is a default serializer for WCF contract. The class and its properties are decorated differently than the
MessageContract. From the annotation point of the view, these is no difference how the source class is written, see the following picture:
OK, but here is something different. The custom
AnnotationAttribute has additional properties to control the annotation exporting process. The following picture gives you more details:
As the above example shows, the
xs:annotation/xs:appinfo element has Surrogate child element. This is a feature of the
XsdDataContractExporter.Option.DataContractSurrogate property. This is the place where we can plug-in our custom surrogate for annotation. In this article, the
Annotation class has been created for this purpose, see later for more details. Switching between the string type and custom surrogate type is done by control property in the
AnnotationAttribute. The above picture shows a result of this selection in the
FirstName element, where surrogate is a
The other feature of the WCF Service annotation is having the capability for controlling the annotation in the export metadata from the service. This task can be accomplished by custom service behavior and configuration in the config section. The following code snippet shows this extension:
<annotation enable='true' exportAsText='false'/>
<annotation .../> element represents a master switcher for using hard coded C# Xml Comments and/or custom attributes such as
AnnotationAttribute. Note, that this extension is an optional to the hardcoded setup such as
exportAsText=false (using a surrogate annotation object).
My solution also includes a small tool called
MetadataViewer (see the following picture) that obtains the metadata from any public endpoint or contract assembly. This should provide better/full picture about the exported WCF Service Metadata. Using an embedded XmlNotepad2007 form, we can see the Metadata Tree. According to my earlier description, there are more than one MetadataSection. The first one is occupied by
wsdl:definitions and the other ones by XML schemas. Note, the MetadataViewer is a standalone small tool that can be used for retrieving metadata from wsdl and mex endpoints (web services and wcf services) with a standard binding.
Ok, back to the initial thinking about the annotations in the Service Metadata.
Basically the service metadata such as wsdl document and XML schemas can be annotated in the following ways:
- on-line, as part of the generating service metadata export based on the operation request such as wsdl or mex
- off-line, where an exported service metadata is annotated by external tool, for instance: Altova
As you can see, both cases require public access to the existing service, in other words, the service has to be deployed and ran. The other case is an annotation of the metadata during the modeling time, where metadata is created in the Contract First fashion, for example: please see my recent article Contract Model for Manageable Services. In this case, the annotations are stored in the Repository like another resource. This approach will be more interesting, when upcoming Microsoft new model driven platform (OSLO) will be introduced at PDC 2008 at the end of this month.
Ok, that's all for now, I hope you got the overall picture about the annotation in the service metadata. Let's start digging in the design and implementation of the WCF Service Extension for exporting annotations.
The design and implementation of the metadata annotation in the WCF Service model is based on the
System.ServiceModel.Description.WsdlExporter extension by implementing its interface
IWsdlExportExtension methods such as
ExportEndpoint. Plumbing these methods on the endpoint or contract behaviors we can get the control for customizing exported metadata.
The following picture shows a class diagram of the
DocumentationAttribute object for intercepting WsdlExport process:
The DocumentAttribute class implements few interfaces such as
IServiceBehavior interface for passing the configuration properties from the behavior extension,
IOperationBehavior for injecting a custom
DataContractAnnotationSurrogate and of course the
Implementation of these interfaces are straightforward and well documented in the MSDN and WCF Samples, where examples for custom DataContract Surrogate and Wsdl Documentation are available.
I am going to focus only on the implementation of the
MessageContract annotation, which is not supported in the same way as the built-in capability for
DataContract serializer option.
For this purpose, the following class has been designed to encapsulate the annotation process of the class decorated by
MessageContractAnnotation.Export method is invoked by
IWsdlExportExtension.ExportEndpoint and its implementation is shown in the following code snippet:
public static void Export(WsdlExporter exporter, WsdlEndpointConversionContext context)
object messageContractExporterObj = null;
Type type = Type.GetType(
System.ServiceModel, Version=184.108.40.206, Culture=neutral,
if (exporter.State.TryGetValue(type, out messageContractExporterObj))
IDictionary o =
BindingFlags.NonPublic | BindingFlags.Instance).GetValue(
foreach (var item in o.Values)
XmlSchemaElement elem =
BindingFlags.NonPublic | BindingFlags.Instance).GetValue(item, null);
OperationDescription operation =
BindingFlags.NonPublic | BindingFlags.Instance).GetValue(item, null);
var operAnnotation =
false).FirstOrDefault() as DocumentationAttribute;
if (operAnnotation != null)
if (ExportAnnotationForMessageBody(exporter, operation, elem)) continue;
if (ExportAnnotationForMessageHeaders(exporter, operation, elem)) continue;
if (ExportAnnotationForMessageParameters(exporter, operation, elem)) continue;
I mentioned earlier that, the
DataContract serializer has a built-in option to inject a custom surrogate for annotating metadata components. In the case of the
MessageContract, this feature is missing, therefore the challenge was to find the way to intercept and customize the metadata exporting process.
The process of the
MessageContract exporting is driven by internal class such as
XmlSerializerMessageContractExporter. Its abstract class has a protected nested class
MessageExportContext, see the following code snippet from the Reflector:
IWsdlExportExtension.ExportEndpoint will call our interceptor, all dictionaries in the above class are already populated. For the annotation process, we need to have an
ElementTypes dictionary. The following code snippet from the Reflector shows this class:
Again, as you can see, the class is internal, therefore I used, in the above Export method, reflection to obtain
XmlSchemaElement and related
OperationDescription. The instance of the
XmlSerializerMessageContractExporter is obtained from the WsdlExporter.State.
Once we have access to the
XmlSchemaElement and its operation, the rest of the implementation is very light and straightforward. Let's look at how the
MessageHeader annotation is implemented, the following code snippet shows that:
internal static bool ExportAnnotationForMessageHeaders(
WsdlExporter exporter, OperationDescription operation, XmlSchemaElement elem)
bool retVal = false;
MessageDescription md =
e=>e.Headers.Count > 0 && e.Headers.FirstOrDefault(h=>h.Name ==elem.Name)!=null);
if (md != null)
MemberInfo mi = md.Headers.FirstOrDefault(h => h.Name == elem.Name).MemberInfo;
var attribute = mi.GetCustomAttributes(
typeof(AnnotationAttribute), false).FirstOrDefault() as AnnotationAttribute;
if (attribute != null)
elem.Annotation = CreateXmlSchemaAnnotation(
attribute.Annotation, attribute.ExportXmlDoc, mi);
retVal = true;
As you can see, the first step is to query the
OperationDescription to get the MessageDescription with a specific header name. Then, we can obtain an
AnnotationAttribute from the memberInfo and then invoke the helper method to create a target
XmlSchemaAnnotation element - see the following code snippet:
internal static XmlSchemaAnnotation CreateXmlSchemaAnnotation(
string text, bool bExportXmlDoc, MemberInfo memberInfo)
XElement element = null;
XmlDocument doc = new XmlDocument();
if (memberInfo != null && bExportXmlDoc)
Type type =
memberInfo.DeclaringType == null ? (Type)memberInfo : memberInfo.DeclaringType;
string memberName = XmlDocumentation.CreateMemberName(memberInfo);
element = XmlDocumentation.Load(memberName, type);
if (element == null)
element = new XElement("member", new XText(text));
XmlSchemaAnnotation annotation = new XmlSchemaAnnotation();
XmlSchemaDocumentation documentation = new XmlSchemaDocumentation();
documentation.Markup = doc.DocumentElement.ChildNodes.Cast<XmlNode>().ToArray();
The responsibility of the above method is to create an annotation element XmlSchemaElement based on the C# Xml Comments and AnnotationAttribute. There is a
XmlDocumentation class for encapsulating the logic in order to obtain the C# Xml Comments element published in the specific file. This logic is divided into two steps, where the first step is to create a unique name based on the class member info such as
XmlDocumentation.CreateMemberName method and the second step is to use this unique name for querying the xml documentation file to get the xml elements - method
Note that using the C# XML Comments must be enabled in the project by setting a path to the file, where these comments are going to be stored in the flat xml fashion.
That's all, let's do some testing.
The solution for WCF Service Extension for metadata annotation is divided into the following 3 projects:
The first project is a standalone Windows Form application for retrieving metadata from any wsdl or mex enabled endpoints. In addition, there is a feature for getting the metadata of the service contract located in the assembly. The second project is a host console program for demonstrating different contracts and operations. Finally, the third project is
WcfAnnotation that includes full implementation described in this article. This assembly must be included to your solution in order to use the features of this article.
WcfAnnotation solution has been written and tested in the Visual Studio 2008 SP1 + .NetFx 3.5 SP1.
Testing annotations in the WCF Service Metadata is very straightforward based on the following steps:
- Launch the
TestServer console program
- Launch the
- Click on
Get button to get metadata from the url endpoint (for instance:
- Check metadata in the TreeView or Xml tab
The following picture shows a portion of the last MetadataSection for
That's all. You are ready to annotate your WCF Service. Please, have a look at the
Contracts.cs file in the TestServer project for usage of these custom attributes.
This article described an extension to WCF Service for exporting Metadata annotations. This feature is not built-in the WCF paradigm, but it can be easily added. The annotation is an optional element in the Metadata and having this human readable information embedded in the wsdl documentation and/or xml schemas is giving more explanation about the service contract for its consumers.
Upcoming Microsoft vision for modeling platform, the metadata are stored in the repository where they play a key position between the logical model and decentralized runtime components (services, applications, etc.). Having more annotations of the metadata is a significant advantage for modeling and discovery. The Repository can easily hold thousands of resources such as endpoints, bindings, contracts, messages, schemas, policies, etc. The annotation will be a good helper for discovery and managing metadata in the Repository.
We can hear more details about the modeling strategy at the Microsoft PDC 2008 conference, where project OSLO and its technologies will be introduced. See you there.