Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

WCF Web Service Proxy Generation Problems


:P
On this page:

So I’m a latecomer to the WCF party and just to check things out I decided to run a quick check against some existing complex Web Services I have running on my site. I created a new WinForms project and added a new Service Reference (installed with the Orcas bits).

 

The importer managed to find my Web Service and create a reference to it. However, the generated code will not compile. On closer inspection the generated Service code is apparently duplicating all the objects that are being returned from the server and their base classes.

 

The Web Service lives here:

http://www.west-wind.com/webstoresandbox/service/WebStoreConsumerService.asmx

 

For example here are two class definitions for a returned entity type:

 

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]

[System.Runtime.Serialization.DataContractAttribute(Namespace="http://www.west-wind.com/WebStoreService/")]

[System.SerializableAttribute()]

public partial class wws_itemsRow : WcfFrontEnd.WebStoreService.wwDataRowContainer

 

 

/// <remarks/>

[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.30")]

[System.SerializableAttribute()]

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.west-wind.com/WebStoreService/")]

public partial class wws_itemsRow : wwDataRowContainer

 

 

Both of these types are defined in the same class file and since they’re marked as partial they are combined which of course causes a compiler problem. I can remove the first set of duplicated classes and the code will then compile and run after I also remove the second binding from app.config (for Soap12).

 

So apparently it looks like the service parser is getting confused by the two bindings exposed from the server. I could probably also fix this by creating an explicit single binding on the server, but it seems that WCF should do the right thing with this (and more specifically for the client side should make a best guess on the best binding to use if more than one exists).

 

Now I’m pretty green concerning WCF – anybody know if this is a glitch with the current service importer or am I missing something obvious here?

 

 

Ok, so not the best experience for the first try but looking over what gets generated and how the configuration settings are set up, this looks to be a much more slick and extensible way to deal with Web Services. For one thing I like the fact that the proxy class is essentially extensible by way of the partial class interface.

 

From a pure Mort perspective WCF can work much in the same way as plain ASMX Web Services work which is great. The service importer creates the appropriate proxies and sets the appropriate bindings and configuration settings in the APP.CONFIG file (lots of options but it’s reasonably obvious what they’re doing – first look seems like they nailed the settings to expose at this level pretty good without overwhelming you!). The code you write with the default proxy is not any different than with the ASMX client:

 

// *** Using the stock proxy

WebStoreService.WebStoreServiceSoapClient service =
                  new WcfFrontEnd.WebStoreService.WebStoreServiceSoapClient();

WebStoreService.wws_itemsRow Item = service.DownloadInventoryItem("WCONNECT");

However you also get lower level control so you can set up the channel on your own which presumably would allow using other bindings like TCP/IP, Pipes or WS style messages. But what’s really nice is that it’s relatively straight forward to set up a channel and binding with simple code like this which does the same as the code above:

 

// *** Using 'manual' channel proxy           

EndpointAddress ep = new EndpointAddress("http://www.west-wind.com/webstoresandbox/service/WebStoreConsumerService.asmx");

           

// *** WebStoreServiceSoap is the service Interface here - generated by the Service Proxy tool, but you can explicitly create this

WebStoreService.WebStoreServiceSoap proxy = ChannelFactory<WebStoreService.WebStoreServiceSoap>.CreateChannel(new SecureHttpBinding(), ep);

 

WebStoreService.wws_itemsRow Item = service.DownloadInventoryItem("WWHELP40");

 

MessageBox.Show(Item.Descript);

 

I cheated with this though <g> because I’m using the Service Interface and result type message classes generated by the Service importer, but still I really like the fact that we’ll be able to have so much more control over the Service interface, especially if both the client and server are running WCF which would allow dynamically choosing the Bindings used to communicate with the remote service.

 

It also seems that WCF is considerably faster in making Web Service calls – especially the first call compared to using standard Web references. With standard Web References there seems to be a inordinately long delay for the first Web Service call as the CLR JITs all the related XML and Web Service components – the WCF calls seem to not have this particular issue.

 

So I’m just kind of shooting off the top of my head here. WCF is meant to do interface based service definitions which is fine in all the samples you see because the samples are typically simple, return simple values. But if you create services that deal with complex types all of this gets a lot more complicated as the client has to be able to rehydrate returned objects as in this Web Service example. The Contract First folks would probably cry blasphemy at this generated  Service Proxy, but looking at all these related objects and classes created in the generated proxy service class, it looks like a tremendous amount of work would be required to manually create related interfaces. <shrug>

 

And is WCF going to make it easier to create client proxies that can serialize into true objects (ie. My existing business objects vs. a generated ‘message’ object).

 

Looking at all the attributes defined at the top of the class here doesn’t make me hopeful <s>…

 

    [System.Xml.Serialization.XmlIncludeAttribute(typeof(wws_itemsRow))]

    [System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.30")]

    [System.SerializableAttribute()]

    [System.Diagnostics.DebuggerStepThroughAttribute()]

    [System.ComponentModel.DesignerCategoryAttribute("code")]

    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.west-wind.com/WebStoreService/")]

    public partial class wwDataRowContainer

 

Ah, it will take some time spelunking through all of this stuff to get a full handle on this. I’ve been reading through Michelle Bustamonte’s WCF Book preview which has been very useful in getting started and up to speed. I just wish the book was out already because reading PDF docs is a PITA <s>… Hurry up Michelle.

Posted in WCF  

The Voices of Reason


 

Phil George
November 12, 2008

# re: WCF Web Service Proxy Generation Problems

Hello from France,

First off you probably want to delete the spam message above this one!

Secondly, I'm just getting in to WCF and I'm a lot later than you! I'm also looking for a way to have my WCF client be able to understand that the object returned by one service call is in fact the exact same type expected by a method exposed by a different service.

In coding terms :

Service1.Person person = Service1.GetPerson(PersonID);
Service2.AddPersonToTeam(person);

Will not work. Nor will casting etc. My only solution so far is to recreate the object client side and fill it with the values from the other object. As you say, a right PITA!

Did you find a nice way around this?

Rick Strahl
November 12, 2008

# re: WCF Web Service Proxy Generation Problems

There's no workaround for this short of modifying the generated proxy classes. This is because each proxy gets generated independently so each of the types are generated in separate namespaces which makes them effectively completely different types even though they have the exact same signature.

There are a couple of ways around this. You can modify the generated proxy and substitute your own types in the service signatures to replace those generated by the proxy generator. This involves changing the generated code - so this is often problematic if you need to re-gen the service proxy later.

But really in 'proper service terms' this is not the right way to go. Results returned from a service are not supposed to be types mapped into your applications but are supposed to be 'messages' that only contain transport data. Meaning that this behavior is by design and you are expected to read and write the values of these message types explicitly and marshall them between your real application types - generally by manually copying values.

A shortcut for this is to copy object data members using some copy object helper functions (using Reflection) which can make this less code intensive. It's ugly and relatively slow, but it works to reduce code. I've often wondered why .NET doesn't provide a decent built-in mechanism to do this - it would be helpful in many scenarios. <shrug> But it's not difficult to build one of your own especially if you are dealing with flat objects.

Jac
October 13, 2009

# re: WCF Web Service Proxy Generation Problems

We had a similar issue and this is wile adding WCF reference in silverlight projects
it was resolved the following way

1) Create a library with the specfied type (on client side - in our case silverlight)
2) Create a library with the "SAME NAMESPACE" and add the file as "LINK" to it.
3) Refer the serverside library in both the wcf services
4) Add the reference of the client library to the project where you are going to create the service proxy
5) When you configure the serviceproxy on the client, select the option to reuse the types from referenced assemblies.

This worked in SL2. But donno why it is not reusing the types referenced assebblies in SL3 but creating proxy objects for those too.
May be it works in you case.

Thanks
Jac

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024