Ответ 1
Когда я использую Visual Studio для создания WCF-клиента ( "Добавить ссылку на службу" ), и я нажимаю "Дополнительно...", флажок, который говорит "Всегда создавать контракты с сообщениями", правильно контролирует, являются ли объекты договора сообщения генерируется.
Это не правильно. Попробуйте с проблемным WSDL из ссылки, и вы получите те же результаты, что и при использовании ServiceContractGenerator
. Фактически, флаг ServiceContractGenerationOptions.TypedMessages
(по умолчанию выключен) напрямую соответствует опциональному диалоговому окну и используется (при включении) до force создание контрактов сообщений.
С учетом сказанного проблема заключается в WSDL и указывается в сгенерированном файле .cs
с такими строками:
//CODEGEN: создание контракта с сообщением, так как имя входа элемента из пространства имен http://localhost/FinSwitch/ не отмечено nillable
Так что проблема. Оба диалоговых окна svcutil.exe
, "Добавить служебную ссылку" и ServiceContractGenerator
не будут разворачивать методы, когда элемент метода или элемент ответа содержит элементы "тип объекта" (строка, base64Binary и т.д.), Не отмеченные nillable="true"
.
Например, вот часть проблемного 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>
который генерирует
// 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);
плюс классы контактов сообщения.
Однако, если мы изменим его на:
<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>
тогда сгенерированный код как ожидалось
[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);
и никаких классов контракта сообщений.
Что все это значит? Это правило жестко закодировано в инфраструктуре (если кому-то интересно, здесь является исходным источником) и не может быть изменен. Можно предварительно обработать содержимое WSDL (после всего, это XML) и вставить nillable="true"
там, где это необходимо, но я не уверен, что можно считать правильным действием - AFAIK, это ответственность поставщика услуг за предоставление правильного WSDL и нет никакой гарантии, что его изменение не вызовет побочных эффектов.