Search code examples
c#.netweb-servicestypescoerce

Coerce types in different namespaces with Identical layout in C#


I've started writing an interface for FedEx's webservice APIs. They have 3 different APIs that I'm interested in; Rate, Ship, and Track. I am generating the service proxies with SvcUtil.exe.

The different service endpoints are each specified by FedEx in their own WSDL files. Each service endpoint has it's own xml namespace (e.g. http://fedex.com/ws/rate/v5 and http://fedex.com/ws/ship/v5)

The service endpoints do use quite a few identical types such as Address, Measurements, Weight, AuthenticationDetail, ClientDetail, etc...

And here is where the problem lies, I can provide all the WSDL files at the same time to SvcUtil.exe and normally it would coalesce any identical types into a single shared type, but since each of FedEx's services are in their own namespace, and they redeclare these types in each WSDL file under that namespace what I end up with instead is an Address, Address1, and Address2 one for each namespace.

To solve that issue, what I do now is to run each WSDL through svcutil separately and put them each in their own .NET namespace (e.g. FedEx.Rate, FedEx.Ship, FedEx.Track). The problem with this is that now I have a distinct address type in each namespace (Fedex.Rate.Address, FedEx.Ship.Address).

This makes it difficult to generalize the code used between the services like a GetAuthenticationDetail() factory method so I don't have to repeat that code in every place I use the different services.

Is there any way in C# to Coerce FedEx.Rate.Address to FedEx.Ship.Address?


Solution

  • If the types are identical, and you have control over the source classes, you can define a conversion operator in the class, and any function that takes a Rate.Address will also automatically take a Ship.Address. For example:

    namespace Rate {
        class Address {
            string Street;
            string City;
            // ...
    
            public static implicit operator Ship.Address(Rate.Address addr) {
                Ship.Address ret;
                ret.Street = addr.Street;
                ret.City = addr.City;
                // ...
    
                return ret;
            }
        }
    }
    

    My C# is a little rusty but I hope you get the idea.