Resolving data contracts shared between multiple WCF services with SvcUtil

If you’re using the SvcUtil.exe tool to generate proxies for WCF services, before long you may hit a problem where the same data contract shared between two services results in a compiler error at the client. You could just specify a different namespace for each service proxy but then you’ll have exactly the same data contract type defined under separate namespaces which is a rather clumsy solution. You could also use the /excludeType switch, but you still have to remember which service should and shouldn’t be exporting a particular type which again isn’t ideal, especially if you have a lot of data contracts to filter out.

The problem
When you decorate a type with the DataContract attribute and use it as a parameter in a service operation, SvcUtil will automatically generate a declaration for that type in the proxy code file which it outputs. This is obviously so that a service client can instantiate the data contract type client-side, and use it to receive and send data to the service (via message serialisation). So far so good. The problem occurs when you have a data contract in a common assembly which is shared between several services, because the data contract will be declared in multiple proxy code files as shown below. When you try to compile the service client, it complains because the same type is declared more than once.

The Solution
The way to solve this without messy namespace workarounds relies on you having access to the same shared assembly which contains the data contract declarations used by the services. Specify a reference to the shared assembly in the SvcUtil command line using the /reference (or shorthand /r) switch:

svcutil.exe http://<your service url>?wsdl /t:code /reference:<path>\CommonAssembly.dll

This tells SvcUtil to generate the proxy code file without including a declaration for the data contract on the assumption that the client will then reference the shared assembly directly to make the data contract type declaration visible.  This way, the data contract can be used in multiple places but only declared once.

This diagram shows the logical relationships between the shared assembly, the client and the services. But obviously in a real deployed environment the client would have a separate copy of the shared assembly. Unfortunately if you don’t have access to a copy of the shared data contracts assembly used by the services, then this solution will not work for you and you will have to specify different namespaces on the command line using the /namespace switch, or exclude data contracts from all but one service using the /excludeType switch (or some alternative means).

As a final design point, your WCF service implementations should be contained in one assembly, the service (.svc) files should be in another, and finally your WCF service contracts and data contracts should be in a separate assembly of their own. By doing this, it makes sharing service and data contracts between different services and client applications very easy and avoids exposing service implementation details to the client.  Never put implementation and contracts into the same assembly because you seriously limit the flexibility of your application architecture. Divide and conquer.

Advertisements

About Phil Munro

I have been developing commercial desktop and distributed web applications with Microsoft technologies since 1997.
This entry was posted in WCF. Bookmark the permalink.