azheglov
azheglov

Reputation: 5523

How to generate client-side code for multiple WCF services with shared types

I have multiple WCF services that share some data contracts and need to generate client-side code using svcutil.exe. I've run into errors using two most obvious ways to do this and need some help.

But first, here are the services:

[ServiceContract( Namespace = "http://www.me.com/services/" )]
public interface IFooService {
    [OperationContract]
    Response RunFoo( Request request );
}
[ServiceContract( Namespace = "http://www.me.com/services/" )]
public interface IBarService {
    [OperationContract]
    Response RunBar( Request request );
}

Response and Request are defined in a separate assembly:

[DataContract( Namespace = "http://www.me.com/shared/" )]
public class Request {
    [DataMember]
    public int Input { get; set; }
}
[DataContract( Namespace = "http://www.me.com/shared/" )]
public class Response {
    [DataMember]
    public int Result { get; set; }
}

The services are implemented in some trivial way, compiled, published - let's switch to the client side now.

Including both services on the svcutil command line - like this:

svcutil /o:Client.cs http://hostname.com/FooService.svc http://hostname.com/BarService.svc

will result in numerous error messages about duplicated data types, starting with

Error: There was a validation error on a schema generated during export: Source: Line: 1 Column: 9087 Validation Error: The global element 'http://schemas.microsoft.com/2003/10/Serialization/:anyType' has already been declared.

and ending with

Error: There was a validation error on a schema generated during export: Source: Line: 1 Column: 12817 Validation Error: The complexType 'http://www.me.com/shared/:Response' has already been declared.

Generating a client-side file separately for each service avoids these errors:

svcutil /o:Foo.cs http://hostname.com/FooService.svc
svcutil /o:Bar.cs http://hostname.com/BarService.svc

But then definitions of shared types (such as Request and Response) will be duplicated in Foo.cs and then in Bar.cs, resulting obviously in compiler errors.

So, what is the conventional way to generate client-side code consuming such services?

Limitations:

Upvotes: 12

Views: 7431

Answers (5)

Please download WSCFblue-v1-Walkthrough zip from the below link, it might help you acheive it.

http://wscfblue.codeplex.com/releases/view/48529

Upvotes: 0

CJBrew
CJBrew

Reputation: 2787

WSCF Blue may get you closer to a solution if you've not found one already.

http://wscfblue.codeplex.com/

It can produce separate files for each type, overwriting on subsequent operations.

Upvotes: 2

Aditya
Aditya

Reputation: 25

When you run the client utility once you will get a XXXXService.cs and a output.config file.

If you observe the XXXXService class you have everything in a file. You can split these as a seperate IXXXService and XXXService file and the datacontracts file.

Then you can run the utility for the second service and add IXXXService1.cs and 1XXXService.cs file and the same datacontracts you can use to share for these 2.

I am not sure if this can answer your question. I had an example which can help you. You can see some more examples here related to some MVC and WCF stuff.

Upvotes: 0

marc_s
marc_s

Reputation: 754598

Well, basically you can

  • either put your shared types into a separate assembly that the clients can use when generating the client code (which you already dismiss as impossible)

or then:

  • you have to generate each proxy for the services separately, and each service will get its own "copy" of the "Request" and "Response" classes

Either you can share the common assembly - or you can't - I don't see any other choice, really.

Upvotes: 5

Marc Gravell
Marc Gravell

Reputation: 1062945

Since you have rules out a shared DTO assembly (why, btw?), the simplest option in this case looks to be to generate the types in different C# namespaces (i.e. two calls to svcutil), and map the data between the two. Essentially: treat the DTOs from the two services as coincidentally similar.

You can use things like automapper to reduce the work, or you could juts serialize from type A and deserialize into type B (assuming the actual data namespaces etc are identical).

Upvotes: 4

Related Questions