I am writing a program that accesses a SOAP webservice written by a third-party provider.
I need to provide a user and login in the SOAP headers, which is kind of easy, in theory:
- add the webservice reference to Visual Studio
- instantiate a new “XXXXClient” generated class
- set xxx.ClientCredentials.UserName.UserName and xxx.ClientCredentials.UserName.Password
Easy as pie. Except when it’s not. You see, the provider’s webservice is written using php, it does not behave nicely with .Net. When you send the request, you can see on Fiddler that the query is sent and gets a response, but .Net does not like this response, and throws exceptions around.
First problem: it throws a MesssageSecurityException because of empty security headers in the response (see here). I first thought that I had the same problem, so I spent the day resolving the issue following this blog post, but it turns out it’s much more simple. To fix this, you must set the enableUnsecuredResponse in the binding’s security node to true. And in order to do that, your binding must be a customBinding. If you have a complicated binding, good luck switching.
Second problem: the mime type for the request and the response are different (“text/xml” vs “application/soap+xml”). To fix this one, you have to write your own custom text encoder (download the WCF examples at the top), and to do that… you have to create something like a thousand classes with a hundred lines each. Just for a simple mime type mismatch! Do not forget to also copy, from the downloadable examples, the BindingElement, BindingSection, ConfigurationStrings, and MessageVersionConverter !
So, for such a simple task, as is too often the case with Microsoft, I need to rewrite (or copy, here) a whole bunch of stuff, just to modify some pretty mundane and common behavior, which should be configurable in the first place. It shows how extensible WCF is, and how bloated the extending is.
Anyway, here is a working app.config. For the code of the custom text message encoding class, as I said, just copy the MS examples (and don’t forget to rename the types in the bindingElementExtensions).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<system.serviceModel> <extensions> <bindingElementExtensions> <add name="customTextMessageEncoding" type="MyClient.SOAP.CustomMessageBindingSection, MyClient" /> </bindingElementExtensions> </extensions> <bindings> <customBinding> <binding name="ThirdPartyOrderBinding"> <customTextMessageEncoding messageVersion="Soap11" mediaType="text/xml" /> <security authenticationMode="UserNameOverTransport" enableUnsecuredResponse="true" /> <httpsTransport /> </binding> </customBinding> </bindings> <client> <endpoint address="https://www.myservice.com/services/ThirdPartyOrder.php" binding="customBinding" bindingConfiguration="ThirdPartyOrderBinding" contract="MyServiceWS.ThirdPartyOrderPortType" name="ThirdPartyOrderPort" /> </client> </system.serviceModel> |