gpt4 book ai didi

c# - dotnet-svcutil 生成的 WCF 代理(甚至自定义 Channel<>)对于有效的 SOAP 响应返回 null

转载 作者:行者123 更新时间:2023-12-01 23:10:16 35 4
gpt4 key购买 nike

使用 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,没有警告/错误,只有 null。

我还尝试了基于 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>

request response

(编辑)

dotnet-svcutil 2.0.1 生成的 WSUserLoginResponse1 的类定义:

[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>

最佳答案

我像您一样使用您的 wsdl 文件使用 dotnet-svcutil 2.0.1 生成 C# 代码。

我使用 SoapUI mocking service 模拟了 SOAP 端点,触发它,然后在我的机器上运行您的代码(连接到我的本地主机上的模拟端点)。

我在调用 proxy.OpenAsync 时遇到了异常。我收到的异常消息是:

The top XML element 'parameters' from namespace '' references distinct types WSUserLoginRequest and WSUserLoginResponse. Use XML attributes to specify another XML name or namespace for the element or types.

因此,我转到生成的代码内的 WSUserLoginRequest1 ,并向 parametersNamespace 添加了一个值,如所述 here :

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.1")]
[System.ServiceModel.MessageContractAttribute(WrapperName="WSUserLogin", WrapperNamespace="WSWebService", IsWrapped=true)]
public partial class WSUserLoginRequest1
{
// replaced Namespace empty string value with my endpoint url
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://localhost:8181/WSUserLogin", Order=0)]
public WSUserLoginRequest parameters;

public WSUserLoginRequest1()
{
}

// ...
}

更改后,它就正常工作了,我在调用 proxy.WSUserLoginAsync 时收到了响应。

我希望我知道如何通过将值传递到 dotnet-svcutil/namespace 选项来添加该 Namespace 值,但遵循这些SO 帖子( 12 ,尽管它们与 svcutil 相关,而不是 dotnet-svcutil)仅将命名空间添加到生成文件中的其他位置。

此外,正如您所指出的,使用 wsdl.exe 不会生成不必要的 WSUserLoginResponse1,而 svcutil-dotnet 会生成。这似乎是一个已知问题,请参见这里:svcutil generated unneccesary wrapper classes .

我希望它对您的问题有任何值(value)。

关于c# - dotnet-svcutil 生成的 WCF 代理(甚至自定义 Channel<>)对于有效的 SOAP 响应返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60332365/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com