I have been given a wsdl file by a company which will integrate with us, detailing how they expect the interface to look. This file contains a few messages and operations, which have request and response objects as input and output, looking like this (I’m not free to share the file, so this has been slightly anonymized. That also means there might be some typos – if so, sorry!):
<wsdl:types>
<xs:schema>
<xs:simpleType name="user_t">
<xs:restriction base="xs:string">
<xs:minLength value="1" />
<xs:maxLength value="20" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="password_t">
<xs:restriction base="xs:string">
<xs:minLength value="4" />
<xs:maxLength value="128" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="accountId_t">
<xs:restriction base="xs:string">
<xs:minLength value="1" />
<xs:maxLength value="64" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="language_t">
<xs:restriction base="xs:string">
<xs:length value="2" />
</xs:restriction>
</xs:simpleType>
<xs:element name="logon">
<xs:complexType>
<xs:sequence>
<xs:element name="user" type="ns:user_t" />
<xs:element name="password" type="ns:password_t" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="logonResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="accountId" type="ns:accountId_t" />
<xs:element name="language" type="ns:language_t" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="loginRequest">
<wsdl:part name="parameters" element="ns:login" />
</wsdl:message>
<wsdl:message name="loginResponse">
<wsdl:part name="parameters" element="ns:loginResponse" />
</wsdl:message>
<wsdl:operation name="login">
<wsdl:input message="ns:loginRequest" />
<wsdl:output message="ns:loginResponse" />
<wsdl:fault message="ns:InvalidUserException" name="InvalidUserException" />
</wsdl:operation>
I then run svcutil on this file to generate an interface. I’d expect a login method looking something like this (implementation language is C#):
loginResponse login(loginRequest request)
What I get, however, is this:
string login(string user, string password, out string language)
This causes a problem, not only because it is not really “ok” to use out parameters in wcf here, but also because our logging framework explodes when wcf services have out-parameters (we really want to avoid changes into the logging framework, as that would require veryveryvery extensive testing, as it would change everything, everywhere).
EDIT: The plot thickens. There is one method in the wsdl which actually is generated as I expected. It is defined in exactly the same fashion as the other operations, except that the response element is empty:
<xs:element name="fooResponse">
</xs:element>
If I alter the logonResponse element so that it is empty, tada!, it works:
loginResponse login(loginRequest request)
Does this make any sense?
A couple of options come to mind:
Change the Service
Change the service interface. If you don’t own, of course you can’t change it.
Update your logging framework
Doesn’t sound fun, but could theoretically be updated so that the changes only affect those services that actually have out parameters, thereby reducing your regression testing load (test the new service and a subset of the old ones).
Hand code your own proxies
If you don’t like what svcutil is doing, make your own contracts using messages. It’s painful from a maintenance standpoint, but you can craft your own messages.