Objects and Web Services

I've  been asked this question enough both on-line and in person that I thought a blog might be a better way to clear up a common misconception. Consider the following situation.  Your application has implemented a class as follows:

public class Dog
{
   public string Breed;
   public string Fetch()
   {
      return "stick";
   }
}

As well, the application has a web service method defined like the following:

[WebMethod]
public Dog GetDog()
{
   return new Dog();
}

So let's move to the client side. In a typical .NET application, you would add a web reference pointing to the web service that includes the GetDog method just described.  Under the covers, Visual Studio .NET invokes wsdl.exe to generate the proxy class. Because of the magic of this tool, not only is a proxy for the web service created, but so too is a class that represents the Dog class that is returned from GetDog.  This means that, on the client side, there is no need to deploy the assembly that implements the Dog class on the server-side.  Or does it.

If you open up the .cs file generated by adding the Web Reference (you might have to “show all files” in the Solution Explorer then navigate to below the Reference Map in the Web Reference - the file is called Reference.cs), you will find a class called Dog defined. Does the automatic addition of the Dog class make it easy for developers to work with web services?  Yes. Does it cause some level of confusion?  Definitely.  Which is the reason for this post.

Take a close look at the Dog class in Reference.cs.  What you will see is a class that contains all of the public properties that were exposed by the server-side Dog class.  What you will *not* see is any of the business logic that might have been implemented in the server-side Dog class.  Nor will you see any methods, public or otherwise.  In other words, these two classes are absolutely not the same class, regardless of the similarity in naming. 

What kind of problem does this cause? Say you actually deploy the server-side assembly onto the client and try to pass an object of that type (the server-side Dog class, that is) into the web service method call.  The result is that an apparently inexplicable InvalidCastException error gets thrown.  The reason for the exception is because the server-side Dog class is not the same Dog class defined in the proxy class.  That should make sense now, but it throws a lot of new web service developers for a loop.

There is a solution to the problem.  Once the proxy class has been created, edit the Reference.cs file directly.  Remove the Dog class from that file and change the return type for the GetDog method to match the server-side Dog class.  Now the InvalidCastException will go away.  Keep in mind that, should you decide to refresh the Web Reference, then you will have to make these changes again.  So when I do this kind of manipulation, I would typically use wsdl.exe manually to create the proxy class file and they add it into the project.  This eliminates the potential for wiping out the changes accidentally.