【发布时间】:2020-06-05 12:17:49
【问题描述】:
使用 dotnet-svcutil 2.0.1 (dotnet-svcutil --sync --outputDir . http://XXX/?WSDL) 和 System.ServiceModel.* 4.7.0 生成的代理,调用代码和下面的?WSDL。代理根本无法反序列化有效响应,只是返回 null。在 Windows 10 和 macOS Catalina 上尝试了 .NET Core 3.0 和 3.1,结果相同。 Fiddler 请求和响应以及来自服务器的 WSDL(我无法控制的服务器)。
对于代理,我使用@shmao 的set_mode 解决方法(https://github.com/dotnet/wcf/issues/2219) 来避免“不支持JScript/CSharp 脚本”异常。此外,我必须删除 Namespace="" 属性才能使请求部分正常工作。我已经添加了 EventListeners 并从所有事件源中转储了 Verbose 中的所有内容,没有警告/错误,只有空值。
我还尝试了基于 Channel 的 MessageContract/DataContract 方法,最终结果相同为 null (!),我无法利用任何基于 .NET Core WCF 的代码来反序列化给定的响应。
将考虑使用 .NET Core 3.1 WCF 反序列化给定响应的任何解决方案甚至部分解决方案,最好使用 dotnet-svcutil。发现警告/错误甚至手动访问响应字符串仍然是对非 WCF 字符串/基于 HttpRequest 的方法的改进。
WSWebServiceSoapPortClient proxy;
try {
proxy = new WSWebServiceSoapPortClient(new BasicHttpBinding(),
new EndpointAddress("http://XXX"));
await proxy.OpenAsync();
} catch (Exception e) {
Console.WriteLine(e.Message);
return;
}
if (proxy.State == System.ServiceModel.CommunicationState.Faulted) {
System.Console.WriteLine("Unable to connect to the proxy.");
return;
}
var one = new WSUserLoginRequest1(new WSUserLoginRequest() {
userName = "XXX",
userPassword = "XXX",
});
WSUserLoginResponse1 wsUserLoginResponse = null;
try {
wsUserLoginResponse = await proxy.WSUserLoginAsync(one); // returns null
} catch (Exception e) {
Console.WriteLine(e.ToString());
return;
}
来自服务器的相关 WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:tns="WSWebService" name="WSWebService" targetNamespace="WSWebService">
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="WSWebService">
...
<s:complexType name="WSUserLoginRequest">
<s:sequence>
<s:element name="userName" type="s:string" />
<s:element name="userPassword" type="s:string" />
</s:sequence>
</s:complexType>
<s:complexType name="WSUserLoginResponse">
<s:sequence>
<s:element name="userToken" type="s:string" />
<s:element name="wsdlVersion" type="s:string" minOccurs="1" maxOccurs="1" default="2.0.0.0" />
<s:element name="result" type="s:int" />
<s:element name="resultString" type="s:string" />
</s:sequence>
</s:complexType>
...
<wsdl:message name="WSUserLoginSoapIn">
<wsdl:part name="parameters" type="tns:WSUserLoginRequest" />
</wsdl:message>
<wsdl:message name="WSUserLoginSoapOut">
<wsdl:part name="parameters" type="tns:WSUserLoginResponse" />
</wsdl:message>
...
<wsdl:operation name="WSUserLogin">
<wsdl:documentation>Authenticate user using provided username and password.</wsdl:documentation>
<wsdl:input message="tns:WSUserLoginSoapIn" />
<wsdl:output message="tns:WSUserLoginSoapOut" />
</wsdl:operation>
(编辑)
WSUserLoginResponse1 的类定义由dotnet-svcutil 2.0.1 生成:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.1")]
[System.ServiceModel.MessageContractAttribute(WrapperName = "WSUserLoginResponse", WrapperNamespace = "WSWebService", IsWrapped = true)]
public partial class WSUserLoginResponse1 {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace = "", Order = 0)]
public WSUserLoginResponse parameters;
public WSUserLoginResponse1() {
}
public WSUserLoginResponse1(WSUserLoginResponse parameters) {
this.parameters = parameters;
}
}
(编辑 2) 来自 dotnet-svcutil 的 WSUserLoginResponse 建议。
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "WSWebService")]
public partial class WSUserLoginResponse {
private string userTokenField;
private string wsdlVersionField;
private int resultField;
private string resultStringField;
public WSUserLoginResponse() {
this.wsdlVersionField = "2.0.0.0";
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public string userToken {
get {
return this.userTokenField;
}
set {
this.userTokenField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public string wsdlVersion {
get {
return this.wsdlVersionField;
}
set {
this.wsdlVersionField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 2)]
public int result {
get {
return this.resultField;
}
set {
this.resultField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 3)]
public string resultString {
get {
return this.resultStringField;
}
set {
this.resultStringField = value;
}
}
}
(编辑 3) 来自 wsdl.exe 的 WSUserLoginResponse 建议。没有 WSUserLoginResponse1
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1087.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="WSWebService")]
public partial class WSUserLoginResponse : object, System.ComponentModel.INotifyPropertyChanged {
private string userTokenField;
private string wsdlVersionField;
private int resultField;
private string resultStringField;
public WSUserLoginResponse() {
this.wsdlVersionField = "2.0.0.0";
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)]
public string userToken {
get {
return this.userTokenField;
}
set {
this.userTokenField = value;
this.RaisePropertyChanged("userToken");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=1)]
public string wsdlVersion {
get {
return this.wsdlVersionField;
}
set {
this.wsdlVersionField = value;
this.RaisePropertyChanged("wsdlVersion");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=2)]
public int result {
get {
return this.resultField;
}
set {
this.resultField = value;
this.RaisePropertyChanged("result");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=3)]
public string resultString {
get {
return this.resultStringField;
}
set {
this.resultStringField = value;
this.RaisePropertyChanged("resultString");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
(编辑 4) 独立 wsdl。
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:tns="WSWebService" name="WSWebService" targetNamespace="WSWebService">
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="WSWebService">
<s:complexType name="WSUserLoginRequest">
<s:sequence>
<s:element name="userName" type="s:string" />
<s:element name="userPassword" type="s:string" />
</s:sequence>
</s:complexType>
<s:complexType name="WSUserLoginResponse">
<s:sequence>
<s:element name="userToken" type="s:string" />
<s:element name="wsdlVersion" type="s:string" minOccurs="1" maxOccurs="1" default="2.0.0.0" />
<s:element name="result" type="s:int" />
<s:element name="resultString" type="s:string" />
</s:sequence>
</s:complexType>
</schema>
</wsdl:types>
<wsdl:message name="WSUserLoginSoapIn">
<wsdl:part name="parameters" type="tns:WSUserLoginRequest" />
</wsdl:message>
<wsdl:message name="WSUserLoginSoapOut">
<wsdl:part name="parameters" type="tns:WSUserLoginResponse" />
</wsdl:message>
<wsdl:portType name="WSWebServiceSoapPort">
<wsdl:operation name="WSUserLogin">
<wsdl:documentation>Documentation</wsdl:documentation>
<wsdl:input message="tns:WSUserLoginSoapIn" />
<wsdl:output message="tns:WSUserLoginSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="WSWebServiceSoapBinding" type="tns:WSWebServiceSoapPort">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="WSUserLogin">
<soap:operation soapAction="WSUserLogin" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="WSWebService" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="WSWebService" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="WSWebService">
<wsdl:port name="WSWebServiceSoapPort" binding="tns:WSWebServiceSoapBinding">
<soap:address location="https://x.x.x.x:x" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
【问题讨论】:
-
可以添加生成的c#定义
WSUserLoginResponse1吗?另外,为什么它以1结尾-WSUserLoginResponse和 ``WSUserLoginResponse1` 都有吗? -
@HeyJude,WSUserLoginResponse1定义在dotnet-svcutil生成的Reference.cs中,WSUserLoginAsync返回类型为Task
。 -
您没有回答我在评论中提出的问题,所以我想我应该解释一下:我希望您在问题中添加
WSUserLoginResponse1的生成代码,因为它可能没有正确生成.它有时会发生。它以1结尾的事实有点可疑。 -
也许您可以使用 Visual Studio 向导生成必要的代码,看看生成的输出是否与
dotnet-svcutil输出有任何不同? docs.microsoft.com/en-us/dotnet/core/additional-tools/… -
@bunt,我看到你添加了
WSUserLoginResponse1定义,太好了。现在,由于这个类包含一个名为parameters的字段,其类型为WSUserLoginResponse,因此还值得添加那个生成的c#定义。
标签: c# wcf soap .net-core wsdl