Prevent ServiceContractGenerator from generating message contracts (request/response wrappers)
When I use Visual Studio to create a WCF client ("Add Service Reference") and I click on "Advanced...", the checkbox which says "Always generate message contracts" does properly control whether the message contract objects are generated.
That's not correct. Try with the problematic WSDL from the link and you'll get the same results as using ServiceContractGenerator
. In fact, ServiceContractGenerationOptions.TypedMessages
flag (by default off) directly corresponds to the forementioned dialog option and is used (when turned on) to force creation of message contracts.
With that being said, the problem is in the WSDL and is indicated in the generated .cs
file with lines like this:
// CODEGEN: Generating message contract since element name login from namespace http://localhost/FinSwitch/ is not marked nillable
So that's the issue. Both svcutil.exe
, "Add Service Reference" dialog and ServiceContractGenerator
will not unwrap the methods when the method element or response element contains "object type" (string, base64Binary etc.) members not marked with nillable="true"
.
For instance, here is a part from the problematic WSDL:
<s:element name="DownloadFile">
<s:complexType>
<s:sequence>
<s:element type="s:string" name="login" maxOccurs="1" minOccurs="0"/>
<s:element type="s:string" name="password" maxOccurs="1" minOccurs="0"/>
<s:element type="s:string" name="fileType" maxOccurs="1" minOccurs="0"/>
<s:element type="s:dateTime" name="fileDate" maxOccurs="1" minOccurs="1"/>
<s:element type="s:boolean" name="onlyDownloadIfFileChanged" maxOccurs="1" minOccurs="1"/>
<s:element type="s:string" name="companyCode" maxOccurs="1" minOccurs="0"/>
<s:element type="s:string" name="category" maxOccurs="1" minOccurs="0"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="DownloadFileResponse">
<s:complexType>
<s:sequence>
<s:element type="s:base64Binary" name="DownloadFileResult" maxOccurs="1" minOccurs="0"/>
</s:sequence>
</s:complexType>
</s:element>
which generates
// CODEGEN: Generating message contract since element name login from namespace http://localhost/FinSwitch/ is not marked nillable
[System.ServiceModel.OperationContractAttribute(Action="http://localhost/FinSwitch/FinSwitchWebServiceSoap/DownloadFileRequest", ReplyAction="http://localhost/FinSwitch/FinSwitchWebServiceSoap/DownloadFileResponse")]
DownloadFileResponse DownloadFile(DownloadFileRequest request);
plus message contact classes.
However, if we modify it to:
<s:element name="DownloadFile">
<s:complexType>
<s:sequence>
<s:element type="s:string" name="login" nillable="true" maxOccurs="1" minOccurs="0"/>
<s:element type="s:string" name="password" nillable="true" maxOccurs="1" minOccurs="0"/>
<s:element type="s:string" name="fileType" nillable="true" maxOccurs="1" minOccurs="0"/>
<s:element type="s:dateTime" name="fileDate" maxOccurs="1" minOccurs="1"/>
<s:element type="s:boolean" name="onlyDownloadIfFileChanged" maxOccurs="1" minOccurs="1"/>
<s:element type="s:string" name="companyCode" nillable="true" maxOccurs="1" minOccurs="0"/>
<s:element type="s:string" name="category" nillable="true" maxOccurs="1" minOccurs="0"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="DownloadFileResponse">
<s:complexType>
<s:sequence>
<s:element type="s:base64Binary" name="DownloadFileResult" nillable="true" maxOccurs="1" minOccurs="0"/>
</s:sequence>
</s:complexType>
</s:element>
then the generated code is as expected
[System.ServiceModel.OperationContractAttribute(Action="http://localhost/FinSwitch/FinSwitchWebServiceSoap/DownloadFileRequest", ReplyAction="http://localhost/FinSwitch/FinSwitchWebServiceSoap/DownloadFileResponse")]
byte[] DownloadFile(string login, string password, string fileType, System.DateTime fileDate, bool onlyDownloadIfFileChanged, string companyCode, string category);
and no message contract classes.
What does all that mean? The rule is hardcoded deeply in the infrastructure (if someone is interested, here is the reference source) and cannot be changed. One can preprocess the WSDL content (afterall, it's a XML) and insert nillable="true"
where needed, but I'm not sure that can be considered to be a correct action - AFAIK, it's the service provider responsibility to provide the correct WSDL and there is no guarantee that altering it will not cause side effects.