Web Services that take custom classes as parameters
While I’m surprised it didn’t hit me before this subject hit us this week from 3 different angles, which I will describe in the next 3 posts -
One unnecessary casting
When consuming a web service that take an instance of a custom class as a parameter visual studio generates an equivalent class to the one defined by the web service. However – as this is not the class used by the web service but an equivalent class, it is not the same type, which means some sort of casting is required -
Say you have a class called MyClass in namespace MyNamespace defined in an assembly called assemblyA
You then create a web service, which references assembly A and has a single method - MyMethod(MyNamespace.MyClass)
You then move on and create a win form client. Again you reference assemblyA so you could created an instance of MyNamespace.MyClass to pass it to the web service
You go on and add the web reference; at this point Visual Studio generates the proxy to the web service for you, neat, only that it is not aware that you know the definition for MyNamespace.MyClass so it goes and creates a local definition of MyClass.
However, since it’s created as part of the generated web service’s proxy the generated class will be created in the proxy's namespace (say – localhost). So - the new class is localhost.MyClass while you have MyNamespace.MyClass
This means that you can’t just pass MyNamespace.MyClass to the web service. You have to create a localhost.MyClass instance. There are a few ways to convert one to the other, neither of them is very nice and all of them mean casting of some sort which is inefficient.
Of course, if all the logic happens in the winform app you could start with localhost.MyClass to begin with and then you don’t need any casting. But what if MyNamespace.MyClass is shared throughout your enterprise and you get it from somewhere else?
The solution, as introduced to me by Jon Simpson, is simple and elegant, but may raise some concerns from a maintenance perspective -
By intorducing the original class to the generated proxy we can avoid the need to use a localy defined class. to do this we add a “using” statment in the generated to introduce the original namespace (MyNamespace) and then remove the definition of the local class generated by the proxy.
This will make the proxy use our original definition of the class, which means we can now pass MyNamespace.MyClass to the web method. Since the two classes were identical to begin with (one was generated from the other) – they are identical on the wire and therefore no changes are required on the server which already coded to accept this class
As I’ve mentioned – the only problem with this approach is that you are modifying a generated code, which means you will have to modify it again if you update the web reference. A simple macro to do it for you might ease this small issue.