我正在尝试使用我们的某个供应商提供的WSDL来使用SOAP 1.2 API。我尽可能简化了WSDL,只做了一个动作。我遇到的问题是WCF为SOAP请求消息生成的格式与供应商期望的格式或SoapUI生成的格式不匹配。具体而言,信封不包含xmlns:ser="http://some.random.api.here.com/"
,getDeviceList
操作不包含ser:
。
我收到的错误是:
System.ServiceModel.FaultException:Unmarshalling Error: cvc-complex-type.2.4.a:找到无效的内容 元素'userName'。 '{userName,password,clientId, locationId}'是预期的。
据我所知,根据一些研究,这个错误只是意味着肥皂体没有正确格式化,或者服务器需要。
SoapUI生成的请求按预期工作,但.NET不会。我尝试使用Web服务,但我得到了相同的结果。我正在考虑按照here手动更改消息,但似乎WCF应该能够处理这个问题。 WSDL似乎有效,除了不导入安全策略部分外,Svcutil不会抛出任何错误。
我遇到的另一个更小的问题是,即使WSDL将属性username,password,clientid和locationid指定为minoccurs = 0,它们仍然是生成的代理类所要求的。我想找到解决这个问题的方法,但是在我至少得到一些工作之后我可以继续努力。
我已经尝试了多种类型的绑定,如here所述:basicHttpBinding,因为它们也有Soap 1.1服务,WsHttpBinding,以及使用多种设置组合的自定义绑定,但似乎没有任何区别消息的格式。
如果有人对如何设置SOAP消息的格式有任何想法或告诉.NET包含正确的命名空间,我将永远感激,因为我只是出于想法。
SoapUI请求:
POST https://a.randomapi.com/api/ApiService12 HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8
Content-Length: 386
Host: a.randomapi.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.1 (Java/1.8.0_74)
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ser="http://some.random.api.here.com/">
<soap:Header/>
<soap:Body>
<ser:getDeviceList>
<!--Optional:-->
<userName>username</userName>
<!--Optional:-->
<password>password</password>
</ser:getDeviceList>
</soap:Body>
</soap:Envelope>
.NET请求(使用Fiddler捕获):
POST https://a.randomapi.com/api/ApiService12 HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action=""
Host: a.randomapi.com
Content-Length: 645
Expect: 100-continue
Accept-Encoding: gzip, deflate
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
</s:Header>
<s:Body xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<getDeviceList xmlns="http://some.random.api.here.com/">
<userName xmlns="">username</userName>
<password xmlns="">password</password>
<clientId xmlns="">0</clientId>
<locationId xmlns="">0</locationId>
</getDeviceList>
</s:Body>
</s:Envelope>
WSDL:
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://some.random.api.here.com/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="ApiServiceImplService" targetNamespace="http://some.random.api.here.com/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:tns="http://some.random.api.here.com/" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://some.random.api.here.com/">
<xs:import namespace="http://www.w3.org/2005/05/xmlmime"/>
<xs:element name="faultInfo">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="faultCode" type="xs:string"/>
<xs:element minOccurs="0" name="reason" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="getDeviceList" type="tns:getDeviceList"/>
<xs:element name="getDeviceListResponse" type="tns:getDeviceListResponse"/>
<xs:complexType name="getDeviceList">
<xs:sequence>
<xs:element minOccurs="0" name="userName" type="xs:string"/>
<xs:element minOccurs="0" name="password" type="xs:string"/>
<xs:element minOccurs="0" name="clientId" type="xs:long"/>
<xs:element minOccurs="0" name="locationId" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="getDeviceListResponse">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="device" type="tns:deviceInfo"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="deviceInfo">
<xs:sequence>
<xs:element minOccurs="0" name="client" type="tns:provInfo"/>
<xs:element minOccurs="0" name="deviceAlias" type="xs:string"/>
<xs:element minOccurs="0" name="deviceId" type="xs:long"/>
<xs:element minOccurs="0" name="deviceIp" type="xs:string"/>
<xs:element minOccurs="0" name="deviceName" type="xs:string"/>
<xs:element minOccurs="0" name="location" type="tns:provInfo"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="provInfo">
<xs:sequence>
<xs:element name="id" type="xs:long"/>
<xs:element minOccurs="0" name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="ApiWebFaultException" nillable="true"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="ApiWebFaultException">
<wsdl:part element="tns:ApiWebFaultException" name="ApiWebFaultException"></wsdl:part>
</wsdl:message>
<wsdl:message name="getDeviceList">
<wsdl:part element="tns:getDeviceList" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getDeviceListResponse">
<wsdl:part element="tns:getDeviceListResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="ApiService">
<wsdl:operation name="getDeviceList">
<wsdl:input message="tns:getDeviceList" name="getDeviceList">
</wsdl:input>
<wsdl:output message="tns:getDeviceListResponse" name="getDeviceListResponse">
</wsdl:output>
<wsdl:fault message="tns:ApiWebFaultException" name="ApiWebFaultException">
</wsdl:fault>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ApiServiceImplServiceSoapBinding" type="tns:ApiService">
<soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsp:PolicyReference URI="#UsernameTokenPolicy"/>
<wsdl:operation name="getDeviceList">
<soap12:operation soapAction="" style="document"/>
<wsdl:input name="getDeviceList">
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output name="getDeviceListResponse">
<soap12:body use="literal"/>
</wsdl:output>
<wsdl:fault name="ApiWebFaultException">
<soap12:fault name="ApiWebFaultException" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ApiServiceImplService">
<wsdl:port binding="tns:ApiServiceImplServiceSoapBinding" name="ApiServiceImplPort">
<soap12:address location="https://a.randomapi.com/api/ApiService12"/>
</wsdl:port>
</wsdl:service>
<wsp:Policy xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" wsu:Id="UsernameTokenPolicy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
</wsp:Policy>
</sp:TransportBinding>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken11/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</wsdl:definitions>
生成的代码:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1067.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://some.random.api.here.com/")]
public partial class getDeviceList : object, System.ComponentModel.INotifyPropertyChanged {
private string userNameField;
private string passwordField;
private long clientIdField;
private bool clientIdFieldSpecified;
private long locationIdField;
private bool locationIdFieldSpecified;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)]
public string userName {
get {
return this.userNameField;
}
set {
this.userNameField = value;
this.RaisePropertyChanged("userName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=1)]
public string password {
get {
return this.passwordField;
}
set {
this.passwordField = value;
this.RaisePropertyChanged("password");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=2)]
public long clientId {
get {
return this.clientIdField;
}
set {
this.clientIdField = value;
this.RaisePropertyChanged("clientId");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool clientIdSpecified {
get {
return this.clientIdFieldSpecified;
}
set {
this.clientIdFieldSpecified = value;
this.RaisePropertyChanged("clientIdSpecified");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=3)]
public long locationId {
get {
return this.locationIdField;
}
set {
this.locationIdField = value;
this.RaisePropertyChanged("locationId");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool locationIdSpecified {
get {
return this.locationIdFieldSpecified;
}
set {
this.locationIdFieldSpecified = value;
this.RaisePropertyChanged("locationIdSpecified");
}
}
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));
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1067.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://some.random.api.here.com/")]
public partial class provInfo : object, System.ComponentModel.INotifyPropertyChanged {
private long idField;
private string nameField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)]
public long id {
get {
return this.idField;
}
set {
this.idField = value;
this.RaisePropertyChanged("id");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=1)]
public string name {
get {
return this.nameField;
}
set {
this.nameField = value;
this.RaisePropertyChanged("name");
}
}
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));
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1067.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://some.random.api.here.com/")]
public partial class deviceInfo : object, System.ComponentModel.INotifyPropertyChanged {
private provInfo clientField;
private string deviceAliasField;
private long deviceIdField;
private bool deviceIdFieldSpecified;
private string deviceIpField;
private string deviceNameField;
private provInfo locationField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)]
public provInfo client {
get {
return this.clientField;
}
set {
this.clientField = value;
this.RaisePropertyChanged("client");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=1)]
public string deviceAlias {
get {
return this.deviceAliasField;
}
set {
this.deviceAliasField = value;
this.RaisePropertyChanged("deviceAlias");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=2)]
public long deviceId {
get {
return this.deviceIdField;
}
set {
this.deviceIdField = value;
this.RaisePropertyChanged("deviceId");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool deviceIdSpecified {
get {
return this.deviceIdFieldSpecified;
}
set {
this.deviceIdFieldSpecified = value;
this.RaisePropertyChanged("deviceIdSpecified");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=3)]
public string deviceIp {
get {
return this.deviceIpField;
}
set {
this.deviceIpField = value;
this.RaisePropertyChanged("deviceIp");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=4)]
public string deviceName {
get {
return this.deviceNameField;
}
set {
this.deviceNameField = value;
this.RaisePropertyChanged("deviceName");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=5)]
public provInfo location {
get {
return this.locationField;
}
set {
this.locationField = value;
this.RaisePropertyChanged("location");
}
}
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));
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://some.random.api.here.com/", ConfigurationName="ServiceReference5.ApiService")]
public interface ApiService {
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
[System.ServiceModel.FaultContractAttribute(typeof(object), Action="", Name="ApiWebFaultException")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(getDeviceList))]
WebApplication1.ServiceReference5.getDeviceListResponse getDeviceList(WebApplication1.ServiceReference5.getDeviceList1 request);
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
System.Threading.Tasks.Task<WebApplication1.ServiceReference5.getDeviceListResponse> getDeviceListAsync(WebApplication1.ServiceReference5.getDeviceList1 request);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="getDeviceList", WrapperNamespace="http://some.random.api.here.com/", IsWrapped=true)]
public partial class getDeviceList1 {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://some.random.api.here.com/", Order=0)]
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string userName;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://some.random.api.here.com/", Order=1)]
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string password;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://some.random.api.here.com/", Order=2)]
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public long clientId;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://some.random.api.here.com/", Order=3)]
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public long locationId;
public getDeviceList1() {
}
public getDeviceList1(string userName, string password, long clientId, long locationId) {
this.userName = userName;
this.password = password;
this.clientId = clientId;
this.locationId = locationId;
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="getDeviceListResponse", WrapperNamespace="http://some.random.api.here.com/", IsWrapped=true)]
public partial class getDeviceListResponse {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://some.random.api.here.com/", Order=0)]
[System.Xml.Serialization.XmlElementAttribute("device", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public WebApplication1.ServiceReference5.deviceInfo[] device;
public getDeviceListResponse() {
}
public getDeviceListResponse(WebApplication1.ServiceReference5.deviceInfo[] device) {
this.device = device;
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface ApiServiceChannel : WebApplication1.ServiceReference5.ApiService, System.ServiceModel.IClientChannel {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class ApiServiceClient : System.ServiceModel.ClientBase<WebApplication1.ServiceReference5.ApiService>, WebApplication1.ServiceReference5.ApiService {
public ApiServiceClient() {
}
public ApiServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public ApiServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public ApiServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public ApiServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public WebApplication1.ServiceReference5.getDeviceListResponse getDeviceList(WebApplication1.ServiceReference5.getDeviceList1 request) {
return base.Channel.getDeviceList(request);
}
public System.Threading.Tasks.Task<WebApplication1.ServiceReference5.getDeviceListResponse> getDeviceListAsync(WebApplication1.ServiceReference5.getDeviceList1 request) {
return base.Channel.getDeviceListAsync(request);
}
}
调用API的代码: var client = new ServiceReference5.ApiServiceClient();
var request = new ServiceReference5.getDeviceList1();
request.userName = "username";
request.password = "password";
var response = client.getDeviceList(request);
结合/终点:
<endpoint address="https://a.randomapi.com/api/ApiService12"
binding="customBinding" bindingConfiguration="ApiServiceImplServiceSoapBinding1"
contract="ServiceReference5.ApiService" name="ApiServiceImplPort1" />
<customBinding>
<binding name="ApiServiceImplServiceSoapBinding1">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://some.random.api.here.com/': -->
<!-- <wsdl:binding name='ApiServiceImplServiceSoapBinding'> -->
<!-- <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">..</sp:SupportingTokens> -->
<textMessageEncoding messageVersion="Soap12" />
<httpsTransport />
</binding>
</customBinding>