views:

915

answers:

1

In VB.NET (using Visual Studio 2008) my WCF service has an interface something like:

<ServiceContract()> _
Public Interface IThingService
    <OperationContract()> _
    Function GetThingByNumber(ByVal thingNumber As MyKeyClass) As Thing
    <OperationContract()> _
    Function GetThing(ByVal thingId As Guid) As Thing

 ' ...

End Interface

I recently changed two projects with similar code to use a basicHttpBinding rather than a wsHttpBinding. Everything compiles well on the service side. Now, in the a client app I choose "Update Service Reference". In one project, my resulting reference.vb seems correct--under 100 lines with simple wrappers for each method. However, in the other, the resulting reference.vb can't seem to understand what the service is. I get a reference.vb of over 1000 lines that looks like:

 '------------------------------------------------------------------------------
 ' <auto-generated>
 '     This code was generated by a tool.
 '     Runtime Version:2.0.50727.3053
 '
 '     Changes to this file may cause incorrect behavior and will be lost if
 '     the code is regenerated.
 ' </auto-generated>
 '------------------------------------------------------------------------------
 Option Strict On
 Option Explicit On
 Imports System.Data
 Namespace ThingService

 <System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0"),  _
 System.ServiceModel.ServiceContractAttribute(ConfigurationName:="GetThingByVersion.IGetThingByVersion")>  _
 Public Interface IThingService

    'CODEGEN: Parameter 'GetThingByNumberResult' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
    <System.ServiceModel.OperationContractAttribute(Action:="http://tempuri.org/ThingService/GetThingByVersion", ReplyAction:="http://tempuri.org/ hingService/GetThingByVersionResponse"),  _
     System.ServiceModel.XmlSerializerFormatAttribute()>  _
    Function GetThingByNumber(ByVal request As ThingService.GetThingByVersionRequest) As ThingService.GetThingByVersionResponse

    'CODEGEN: Parameter 'GetThingResult' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
    <System.ServiceModel.OperationContractAttribute(Action:="http://tempuri.org/ThingService/GetThing", ReplyAction:="http://tempuri.org/ThingService/GetThingResponse"),  _
     System.ServiceModel.XmlSerializerFormatAttribute()>  _
    Function GetThing(ByVal request As ThingService.GetThingRequest) As ThingService.GetThingResponse
'...
End Interface

 '''<remarks/>
 <System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3082"),  _
 System.SerializableAttribute(),  _
 System.Diagnostics.DebuggerStepThroughAttribute(),  _
 System.ComponentModel.DesignerCategoryAttribute("code"),  _
 System.Xml.Serialization.XmlTypeAttribute([Namespace]:="http://schemas.datacontract.org/2004/07/ThingLibraryCore")&gt;  _
 Partial Public Class MyKeyClass
    Inherits Object
    Implements System.ComponentModel.INotifyPropertyChanged

    Private concatenatedThingNumberField As String
    Private ThingNumberField As Integer
 Private ThingNumberFieldSpecified As Boolean

 '... goes on and on...

It's as if the code generated knows nothing of my actual service interface. Any idea how to troubleshoot this? Thanks in advance.

EDIT: Looks like I need to make sure that the server can use the DataContractSerializer and not the XmlSerializer: see http://blogs.msdn.com/sonuarora/archive/2007/06/16/contract-generation-from-wsdl-xml-schema-datacontractserializer-vs-xmlserializer.aspx . Does anyone know how I can figure out what in my code (probably in Class Thing) is violating the restrictions on DataContractSerializer?

+2  A: 

Honestly, I'm not sure what the answer is. Have you tried deleting the service reference and re-creating it from scratch? That would seem to be the most straightforward way to try to fix it, especially since you've made changes.

I know you didn't ask this, but as an aside, I have personally gotten away from using the service reference feature in visual studio altogether. Here is an excellent video that describes how easy it is to do, providing you are willing to refactor your code a little bit. Since it sounds like you are in charge of both WCF client and server, I think you'd benefit tremendously from the approach Miguel advocates.

EDIT:

In response to John Saunder's comment, if you are in charge of both the client and the server, you'd be better off, in my opinion, to re-factor the contracts (service and data contracts) into a single assembly that is shared between the client and server. When you add/update a service reference, all that does is make a code-generated copy of these contracts for the client and then adds the boilerplate code for the proxy. So in essence, you have two separate, but identical, definitions of these interfaces and classes, one on the server side and one on the client side.

The reason I migrated from doing this is because I have a WCF service hosted in a Windows service. This service was used by clients in four separate assemblies throughout my project. Every time I made a change to the service/data contract for the WCF service, I had to go update the service reference in the four assemblies that used the WCF service. By refactoring these contracts to a single, shared assembly, I update that assembly, re-compile (which I would have to do anyway), and I'm ready to go. I no longer have to remember which assemblies need to be updated.

I realize that many of the examples on the web talk about the simplicity of using the svcutil tool, but in my case, it's unnecessary overhead.

Take a look at the video and judge for yourself.

Matt Davis
I would recommend against this, without a much better reason. Almost all the examples you'll find on the web will be using service references.
John Saunders
Add Service Reference permits you to use types from shared assemblies. Just click the "Advanced" button.
John Saunders
Thanks, Matt--that video was very helpful. Even if I do the "simple" manual client creation (using the ChannelFactory method), I think we will have issues with the way things serialize when dealing with a Dictionary(Of string, TVal). I plan to start simple and go from there.
Patrick Szalapski
@John Saunders, I'll check it out. But even with that, I still have to update the client proxy in each and every location the service is "used" when the interface changes. Re-factoring everything into a single assembly allows me to bypass this headache.
Matt Davis
The video is a good one. I now also recommend avoiding Service References wherever you can ship a new DLL when the service contract changes.
Patrick Szalapski