WCF – Publishing Unreferenced Data Types

February 21, 2013

tags: ,
no comments

The default behavior of WCF services is to expose schemas in the service metadata of the object data graph that is exposed in the service contract.
When consuming the metadata, the default behavior is very similar in the sense that it creates the object data graph that is exposed in the service contract.

In some cases you may want to publish additional data as part of the service metadata even though it isn’t referenced somewhere in the service contract, that is other than the fault contracts, parameters object graph, and the return values.

How can we do that then?
First, I searched in Google and came across this article which provides a way to do so, but I found it to be far from perfect because of the following reasons –

  1. It doesn’t provide a way to dynamically adding unreferenced known types
  2. It doesn’t support composite object graphs where one of the members could be of a type which is already exposed as part of the service metadata, an exception is thrown in this case
  3. It requires the client to use a behavior to get these data contracts, though there are ways to override this

The solution –

My goal was to use the ‘ServiceKnownTypeAttribute’ to include additional data types which are unreferenced in the service metadata.
Unfortunately, when you do that, WCF ignores that type because it is unreferenced by the service and it isn’t generated on the client.

I found a workaround for this though, if you include the type ‘System.Object’ within the referenced data of your service, these additional types would actually be exposed and generated on the client side.
Obviously, I wouldn’t want to enforce the developer to include ‘System.Object’ anywhere in an explicit way such as adding a stub method, because that would basically suck a big time.

The workaround I chose to do was to inject a fault contract of type ‘System.Object’ on a single operation, this has the least impact on the service and would be pretty much hidden from the developers in both sides because it is more of a tagging metadata rather than API.

Doing that, I provide a solution that completes what I was aiming for –

I can define unreferenced data types for my service that may include existing types within them, I can use the dynamic form of the ‘ServiceKnownTypeAttribute’ to define these types dynamically, and it would be generated on the client side without the need for a special behavior on its side too.

It looks as the following –

First we need to add the service behavior which injects the fault contract automatically for us –

Code Snippet
  1. //The behavior that injects the fault contract
  2. host.Description.Behaviors.Add(new UnreferencedTypePublishingBehavior());

Then, we can use the ‘ServiceKnownTypeAttribute’ to include whatever we like –

Code Snippet
  1. [ServiceContract]
  2. [ServiceKnownType(typeof(CommonStatusCode))]
  3. //[ServiceKnownType("GetKnownTypes", typeof(Helper))]
  4. interface IMyService
  5. {
  6.     [OperationContract]
  7.     ActionResult DoJob();
  8.  
  9.     [OperationContract]
  10.     ActionResult DoJobWithNewVersionEnum();
  11. }

That’s it, when the client consumes the metadata, the ‘CommonStatusCode’ would be included in his service reference.

A real-life example

You might wonder where you would need such a thing.
A valuable example would be to use Enum with service versioning in mind to support backward compatibility.
Enum is pretty problematic in terms of service versioning, read here.

Basically, if you change its members, it is considered to be a breaking change because that would blow up existing clients when they would try to deserialize the data with the new value.

As the code sample shows, you can use this approach for using Enum in a way that it would be more fair to service versioning.
Typically, you can use an integer as the value to be transferred but expose the Enum as the additional unreferenced data type.
That way clients can match the integer with the generated Enum and map non-existing data as a default member that represents such cases.

I welcome you to check the code example to get a complete notion of this approach.

Where’s the code?

You can download the code if you like.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*