使用 WCF WsdlExporter 如何创建与 singleWsdl 完全一样的 WSDL?
Posted
技术标签:
【中文标题】使用 WCF WsdlExporter 如何创建与 singleWsdl 完全一样的 WSDL?【英文标题】:With WCF WsdlExporter how to create a WSDL exactly like singleWsdl? 【发布时间】:2020-11-20 08:20:32 【问题描述】:当我创建 WCF 服务应用程序时,我得到了一个具有两种方法的简单服务。如果我运行它,我会得到一个页面,我可以在该页面上单击 singleWsdl 页面。 WSDL 超过 100 行,适用于 SoapUI 和 WcfTestClient。
现在我想使用 WslExporter 创建完全相同的 WSDL。 (见:https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.description.wsdlexporter?view=netframework-4.8)
我的尝试:
WsdlExporter exporter = new WsdlExporter();
exporter.PolicyVersion = PolicyVersion.Policy15;
var myContract = ContractDescription.GetContract(typeof(IService1));
exporter.ExportContract(myContract);
exporter.ExportEndpoint(
new ServiceEndpoint(myContract, new BasicHttpBinding(), new EndpointAddress("http://x.y.z/Service1.svc")));
string wsdl;
using (var sw = new StringWriter())
exporter.GeneratedWsdlDocuments[0].Write(sw);
wsdl = sw.ToString();
return wsdl;
但结果是行数少得多的 WSDL。如果在 WcfTestClient 的 SoapUI 中加载它会产生错误。那么...如何创建一个有效的 WSDL?
*** 编辑 ***
在 Visual Studio 2017 中,我创建了一个新项目:WCF 服务应用程序 这个空项目的一部分是下一个类,在合约中使用:
[DataContract]
public class CompositeType
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
get return boolValue;
set boolValue = value;
[DataMember]
public string StringValue
get return stringValue;
set stringValue = value;
如果我启动它,我会得到这个 WSDL:
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" name="Service1" targetNamespace="http://tempuri.org/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
<xs:import namespace="http://schemas.datacontract.org/2004/07/Turien.Dynamic.Basic"/>
<xs:element name="GetData">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="value" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetDataResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="GetDataResult" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetDataUsingDataContract">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q1="http://schemas.datacontract.org/2004/07/Turien.Dynamic.Basic" minOccurs="0" name="composite" nillable="true" type="q1:CompositeType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetDataUsingDataContractResponse">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q2="http://schemas.datacontract.org/2004/07/Turien.Dynamic.Basic" minOccurs="0" name="GetDataUsingDataContractResult" nillable="true" type="q2:CompositeType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/">
<xs:element name="anyType" nillable="true" type="xs:anyType"/>
<xs:element name="anyURI" nillable="true" type="xs:anyURI"/>
<xs:element name="base64Binary" nillable="true" type="xs:base64Binary"/>
<xs:element name="boolean" nillable="true" type="xs:boolean"/>
<xs:element name="byte" nillable="true" type="xs:byte"/>
<xs:element name="dateTime" nillable="true" type="xs:dateTime"/>
<xs:element name="decimal" nillable="true" type="xs:decimal"/>
<xs:element name="double" nillable="true" type="xs:double"/>
<xs:element name="float" nillable="true" type="xs:float"/>
<xs:element name="int" nillable="true" type="xs:int"/>
<xs:element name="long" nillable="true" type="xs:long"/>
<xs:element name="QName" nillable="true" type="xs:QName"/>
<xs:element name="short" nillable="true" type="xs:short"/>
<xs:element name="string" nillable="true" type="xs:string"/>
<xs:element name="unsignedByte" nillable="true" type="xs:unsignedByte"/>
<xs:element name="unsignedInt" nillable="true" type="xs:unsignedInt"/>
<xs:element name="unsignedLong" nillable="true" type="xs:unsignedLong"/>
<xs:element name="unsignedShort" nillable="true" type="xs:unsignedShort"/>
<xs:element name="char" nillable="true" type="tns:char"/>
<xs:simpleType name="char">
<xs:restriction base="xs:int"/>
</xs:simpleType>
<xs:element name="duration" nillable="true" type="tns:duration"/>
<xs:simpleType name="duration">
<xs:restriction base="xs:duration">
<xs:pattern value="\-?P(\d*D)?(T(\d*H)?(\d*M)?(\d*(\.\d*)?S)?)?"/>
<xs:minInclusive value="-P10675199DT2H48M5.4775808S"/>
<xs:maxInclusive value="P10675199DT2H48M5.4775807S"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="guid" nillable="true" type="tns:guid"/>
<xs:simpleType name="guid">
<xs:restriction base="xs:string">
<xs:pattern value="[\da-fA-F]8-[\da-fA-F]4-[\da-fA-F]4-[\da-fA-F]4-[\da-fA-F]12"/>
</xs:restriction>
</xs:simpleType>
<xs:attribute name="FactoryType" type="xs:QName"/>
<xs:attribute name="Id" type="xs:ID"/>
<xs:attribute name="Ref" type="xs:IDREF"/>
</xs:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/Turien.Dynamic.Basic" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Turien.Dynamic.Basic">
<xs:complexType name="CompositeType">
<xs:sequence>
<xs:element minOccurs="0" name="BoolValue" type="xs:boolean"/>
<xs:element minOccurs="0" name="StringValue" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="CompositeType" nillable="true" type="tns:CompositeType"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="IService1_GetData_InputMessage">
<wsdl:part name="parameters" element="tns:GetData"/>
</wsdl:message>
<wsdl:message name="IService1_GetData_OutputMessage">
<wsdl:part name="parameters" element="tns:GetDataResponse"/>
</wsdl:message>
<wsdl:message name="IService1_GetDataUsingDataContract_InputMessage">
<wsdl:part name="parameters" element="tns:GetDataUsingDataContract"/>
</wsdl:message>
<wsdl:message name="IService1_GetDataUsingDataContract_OutputMessage">
<wsdl:part name="parameters" element="tns:GetDataUsingDataContractResponse"/>
</wsdl:message>
<wsdl:portType name="IService1">
<wsdl:operation name="GetData">
<wsdl:input wsaw:Action="http://tempuri.org/IService1/GetData" message="tns:IService1_GetData_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IService1/GetDataResponse" message="tns:IService1_GetData_OutputMessage"/>
</wsdl:operation>
<wsdl:operation name="GetDataUsingDataContract">
<wsdl:input wsaw:Action="http://tempuri.org/IService1/GetDataUsingDataContract" message="tns:IService1_GetDataUsingDataContract_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IService1/GetDataUsingDataContractResponse" message="tns:IService1_GetDataUsingDataContract_OutputMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="BasicHttpBinding_IService1" type="tns:IService1">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetData">
<soap:operation soapAction="http://tempuri.org/IService1/GetData" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetDataUsingDataContract">
<soap:operation soapAction="http://tempuri.org/IService1/GetDataUsingDataContract" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Service1">
<wsdl:port name="BasicHttpBinding_IService1" binding="tns:BasicHttpBinding_IService1">
<soap:address location="http://localhost/Turien.Dynamic.Basic/Service1.svc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
使用我的代码来提取 WSDL,我得到了这个:
<wsdl:definitions xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="service" targetNamespace="http://tempuri.org/">
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import namespace="http://tempuri.org/"/>
<xsd:import namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
<xsd:import namespace="http://schemas.datacontract.org/2004/07/Turien.Dynamic.Basic"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="IService1_GetData_InputMessage">
<wsdl:part name="parameters" element="tns:GetData"/>
</wsdl:message>
<wsdl:message name="IService1_GetData_OutputMessage">
<wsdl:part name="parameters" element="tns:GetDataResponse"/>
</wsdl:message>
<wsdl:message name="IService1_GetDataUsingDataContract_InputMessage">
<wsdl:part name="parameters" element="tns:GetDataUsingDataContract"/>
</wsdl:message>
<wsdl:message name="IService1_GetDataUsingDataContract_OutputMessage">
<wsdl:part name="parameters" element="tns:GetDataUsingDataContractResponse"/>
</wsdl:message>
<wsdl:portType name="IService1">
<wsdl:operation name="GetData">
<wsdl:input wsam:Action="http://tempuri.org/IService1/GetData" message="tns:IService1_GetData_InputMessage"/>
<wsdl:output wsam:Action="http://tempuri.org/IService1/GetDataResponse" message="tns:IService1_GetData_OutputMessage"/>
</wsdl:operation>
<wsdl:operation name="GetDataUsingDataContract">
<wsdl:input wsam:Action="http://tempuri.org/IService1/GetDataUsingDataContract" message="tns:IService1_GetDataUsingDataContract_InputMessage"/>
<wsdl:output wsam:Action="http://tempuri.org/IService1/GetDataUsingDataContractResponse" message="tns:IService1_GetDataUsingDataContract_OutputMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="BasicHttpBinding_IService1" type="tns:IService1">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetData">
<soap:operation soapAction="http://tempuri.org/IService1/GetData" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetDataUsingDataContract">
<soap:operation soapAction="http://tempuri.org/IService1/GetDataUsingDataContract" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="service">
<wsdl:port name="BasicHttpBinding_IService1" binding="tns:BasicHttpBinding_IService1">
<soap:address location="http://localhost/Turien.Dynamic.Basic/Service.svc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
如您所见,缺少属性BoolValue
和StringValue
的复杂类型/类StringValue
。
【问题讨论】:
现在我正在使用一种解决方法。这对我的 POC 来说已经足够了。下周五我会再试试你的答案。 【参考方案1】:你需要先获取元数据集:
var exporter2 = new WsdlExporter();
exporter2.ExportEndpoint(myServiceEndpoints[0]);
var metadataSet = exporter.GetGeneratedMetadata();
var schemaStream = new MemoryStream();
metadataSet.WriteTo(new XmlTextWriter(new StreamWriter(schemaStream)));
schemaStream.Position = 0;
var source = XDocument.Load(
new XmlTextReader(schemaStream));
Console.WriteLine(source);
拿到metadataSet后,我们需要截取它的内容,因为SOAPUI不能识别MetadataSection,我们只需要提取wsdl:definitions中间的内容。
更新
wsdl:definitions 包含端点信息:
我不确定你那边发生了什么,但在我这边是可行的。我将 source 保存到一个 txt 文件中并删除了不必要的节点。
【讨论】:
感谢您的回答。您选择的部分看起来与我开始的 38 行完全相同。所以我很抱歉,那里没有进展......:/ 我按照你的方法得到的“wsdl:definitions”真的没用,和我之前得到的有点像但又不一样。根据你的方法得到的“wsdl:definitions”没有端点信息可能是这个原因造成的,你可以尝试使用我的代码。 我试过了,没用。 SoapUI 和 WcfTestClient 报错。 我更新了我的回复。 我再次尝试了一个完全干净的新项目。我用这些信息更新了我的问题。你是对的......使用 SoapUI 加载 WDL 文件不会产生错误。但它也不会产生正确的客户端界面。我缺少(在我的示例中)具有 BoolValue 和 StringValue 属性的类CompositeType
。复杂类型完全丢失/为空。您的示例生成与我的示例相同的不完整 WSDL。以上是关于使用 WCF WsdlExporter 如何创建与 singleWsdl 完全一样的 WSDL?的主要内容,如果未能解决你的问题,请参考以下文章