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.
Other Posts you might also like