Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
650 views
in Technique[技术] by (71.8m points)

c# - SOAP requests in .NET

We're trying to use SOAP requests to interact with a booking API using Visual Studio C#.

We've interfaced with a Web Service of another API without issue but this one is proving problematic.

We've added it as a Service Reference and Visual Studio has generated all the classes for it and web.config entries so that all seems well.

However when we try and make a simple request to the client SOAP Service we get the following error:

Namespace='com.hrs.soap.hrs' is not supported with rpcliteral SOAP. The wrapper element has to be unqualified.

The code is:

PingRequest pingrequest = new PingRequest();    
SoapServiceClient service = new SoapServiceClient();
service.ping(pingrequest);

This what's been added in the Web.config file:

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="HRSSoapServiceBinding" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="..."
          binding="basicHttpBinding" bindingConfiguration="HRSSoapServiceBinding"
          contract="HRSService.HRSSoapService" name="HRSSoapServicePort" />
    </client>
  </system.serviceModel>

According to the documentation the request should look like the following:

<complexType name="PingRequest">
    <complexContent>
        <extension base="tns:Request">
            <sequence>
                <element name="echoData" type="xsd:string"/>
            </sequence>
        </extension>
    </complexContent>
</complexType>

Full Stack Trace below:

[InvalidOperationException: Namespace='com.hrs.soap.hrs' is not supported with rpcliteral SOAP. The wrapper element has to be unqualified.]
   System.Xml.Serialization.XmlReflectionImporter.CheckTopLevelAttributes(XmlAttributes a, String accessorName) +842469
   System.Xml.Serialization.XmlReflectionImporter.ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, String ns, Type choiceIdentifierType, Boolean rpc, Boolean openModel, RecursionLimiter limiter) +4072651
   System.Xml.Serialization.XmlReflectionImporter.ImportMemberMapping(XmlReflectionMember xmlReflectionMember, String ns, XmlReflectionMember[] xmlReflectionMembers, Boolean rpc, Boolean openModel, RecursionLimiter limiter) +699
   System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement, Boolean rpc, Boolean openModel, RecursionLimiter limiter) +298

[InvalidOperationException: There was an error reflecting 'HRSException'.]
  System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement, Boolean rpc, Boolean openModel, RecursionLimiter limiter) +1051
   System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(String elementName, String ns, XmlReflectionMember[] members, Boolean hasWrapperElement, Boolean rpc, Boolean openModel, XmlMappingAccess access) +137
   System.ServiceModel.Description.XmlSerializerImporter.ImportMembersMapping(XmlName elementName, String ns, XmlReflectionMember[] members, Boolean hasWrapperElement, Boolean rpc, Boolean isEncoded, String mappingKey) +237
   System.ServiceModel.Description.OperationReflector.ImportMembersMapping(String elementName, String ns, XmlReflectionMember[] members, Boolean hasWrapperElement, Boolean rpc, String mappingKey) +134
   System.ServiceModel.Description.OperationReflector.ImportFaultElement(FaultDescription fault, XmlQualifiedName& elementName) +458
   System.ServiceModel.Description.OperationReflector.GenerateXmlSerializerFaultContractInfos() +153
   System.ServiceModel.Description.OperationReflector.EnsureMessageInfos() +929
   System.ServiceModel.Description.Reflector.EnsureMessageInfos() +98
   System.ServiceModel.Description.XmlSerializerOperationBehavior.CreateFormatter() +32
   System.ServiceModel.Description.XmlSerializerOperationBehavior.System.ServiceModel.Description.IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy) +42
   System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription contract, ClientRuntime proxy, DispatchRuntime dispatch) +94
   System.ServiceModel.Description.DispatcherBuilder.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime) +247
   System.ServiceModel.Description.DispatcherBuilder.BuildProxyBehavior(ServiceEndpoint serviceEndpoint, BindingParameterCollection& parameters) +342
   System.ServiceModel.Channels.ServiceChannelFactory.BuildChannelFactory(ServiceEndpoint serviceEndpoint, Boolean useActiveAutoClose) +85
   System.ServiceModel.ChannelFactory.CreateFactory() +43
   System.ServiceModel.ChannelFactory.OnOpening() +23
   System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +274
   System.ServiceModel.ChannelFactory.EnsureOpened() +107
   System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address, Uri via) +134
   System.ServiceModel.ChannelFactory`1.CreateChannel() +29
   System.ServiceModel.ClientBase`1.CreateChannel() +91
   System.ServiceModel.ClientBase`1.CreateChannelInternal() +26
   System.ServiceModel.ClientBase`1.get_Channel() +261
   BLL.HRSService.HRSSoapServiceClient.ping(HRSPingRequest pingRequest) in C:Code-------BLLService ReferencesHRSServiceReference.cs:15850
   -------.Test.Ping() in C:Code-------Test.aspx.cs:48
   -------.Test.Page_Load(Object sender, EventArgs e) in C:Code-------Test.aspx.cs:24
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +91
   System.Web.UI.Control.LoadRecursive() +74
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207

We installed Fiddler and there is no XML request going through that we can see, presumably because it throws an exception before anything is sent.

What exactly do we need to change in our setup to make this work?

UPDATE

WSDL: Available [here][1]

UPDATE

Following davidfmatheson's excellent advice I've copied the WSDL locally and made the amendments as suggested. I'm still getting the same error although possibly in a different place:

[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
        BLL.HRSService.pingResponse BLL.HRSService.HRSSoapService.ping(BLL.HRSService.pingRequest request) {
            return base.Channel.ping(request);
        }

        public BLL.HRSService.HRSPingResponse ping(BLL.HRSService.HRSPingRequestWrapper ping1) {
            BLL.HRSService.pingRequest inValue = new BLL.HRSService.pingRequest();
            inValue.ping = ping1;
            BLL.HRSService.pingResponse retVal = ((BLL.HRSService.HRSSoapService)(this)).ping(inValue);
            return retVal.pingResponse1;
        }

The line that fails is the return base.Channel.ping(request); with error Namespace='com.hrs.soap.hrs' is not supported with rpcliteral SOAP. The wrapper element has to be unqualified.

I also tried to explicitly set the SOAPBinding:

Exception Details: System.InvalidOperationException: Namespace='com.hrs.soap.hrs' is not supported with rpcliteral SOAP. The wrapper element has to be unqualified.

Source Error: 

Line 15917:        [System.Web.Services.Protocols.SoapDocumentMethod(Use = System.Web.Services.Description.SoapBindingUse.Literal)]
Line 15918:        BLL.HRSService.pingResponse BLL.HRSService.HRSSoapService.ping(BLL.HRSService.pingRequest request) {
Line 15919:            return base.Channel.ping(request);
Line 15920:        }
Line 15921:

OK now I've amended the SOAP Binding style to document in my local WSDL and recreated the classes and I have a different error:

Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'BLL.HRSService.HRSHotelTaxDetail[]' to 'BLL.HRSService.HRSHotelTaxDetail'
error CS0030: Cannot convert type 'BLL.HRSService.HRSHotelAmenityCriterion[]' to 'BLL.HRSService.HRSHotelAmenityCriterion'
error CS0029: Cannot implicitly convert type 'BLL.HRSService.HRSHotelTaxDetail' to 'BLL.HRSService.HRSHotelTaxDetail[]'
error CS0029: Cannot implicitly convert type 'BLL.HRSService.HRSHotelAmenityCriterion' to 'BLL.HRSService.HRSHotelAmenityCriterion[]'

StackTrace:

[InvalidOperationException: Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'BLL.HRSService.HRSHotelTaxDetail[]' to 'BLL.HRSService.HRSHotelTaxDetail'
error CS0030: Cannot convert type 'BLL.HRSService.HRSHotelAmenityCriterion[]' to 'BLL.HRSService.HRSHotelAmenityCriterion'
error CS0029: Cannot implicitly convert type 'BLL.HRSService.HRSHotelTaxDetail' to 'BLL.HRSService.HRSHotelTaxDetail[]'
error CS0029: Cannot implicitly convert type 'BLL.HRSService.HRSHotelAmenityCriterion' to 'BLL.HRSService.HRSHotelAmenityCriterion[]'
]
   System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence) +1024
   System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies) +1997
   System.Xml.Serialization.XmlSerializer.GetSerializersFromCache(XmlMapping[] mappings, Type type) +772
   System.Xml.Serialization.XmlSerializer.FromMappings(XmlMapping[] mappings, Type type) +4066268
   System.ServiceModel.Description.SerializerGenerationContext.GenerateSerializers() +185
   System.ServiceModel.Description.SerializerGenerationContext.GetSerializer(Int32 handle) +102
   System.ServiceModel.Description.MessageInfo.get_BodySerializer() +17
   System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest) +112

[CommunicationException: There was an error in serializing body of message pingRequest: 'Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'BLL.HRSService.HRSHotelTaxDetail[]' to 'BLL.HRSService.HRSHotelTaxDetail'
error CS0030: Cannot convert type 'BLL.HRSService.HRSHotelAmenity

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are trying to consume an RPC-literal service from .NET, so you may have to convert the service to doc-literal. See MSDN Blog.

EDIT: More complete answer

The goal is to be able to use doc-literal, but still send the same message. Let's focus on the ping operation. Right now your WSDL has the type defined as:

<complexType name="HRSPingRequest">
    <complexContent>
        <extension base="tns:HRSRequest">
            <sequence>
                <element name="echoData" type="xsd:string"/>
            </sequence>
        </extension>
    </complexContent>
</complexType>

And your message defined as:

<message name="HRSSoapService_pingRequest">
    <part name="pingRequest" type="tns:HRSPingRequest"/>
</message>

And your binding defined as:

<binding name="HRSSoapServiceBinding" type="tns:HRSSoapService">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="ping">
        <soap:operation soapAction=""/>
        <input>
            <soap:body namespace="com.hrs.soap.hrs" use="literal"/>
        </input>
        <output>
            <soap:body namespace="com.hrs.soap.hrs" use="literal"/>
        </output>
        <fault name="HRSException">
            <soap:fault name="HRSException" use="literal"/>
        </fault>
    </operation>
</binding>

So locally we change the "rpc" to "document" and then fix the WSDL to actual document/literal:

<element name="ping" type="tns:HRSPingRequestWrapper" />
<complexType name="HRSPingRequestWrapper">
    <sequence>
        <element name="pingRequest" type="tns:HRSPingRequest" />
    </sequence>
</complexType>
<complexType name="HRSPingRequest">
    <complexContent>
        <extension base="tns:HRSRequest">
            <sequence>
                <element name="echoData" type="xsd:string"/>
            </sequence>
        </extension>
    </complexContent>
</complexType>

...

<message name="HRSSoapService_pingRequest">
    <part name="pingRequest" element="tns:ping"/>
</message>

Now generate off of this WSDL and see if it sends a ping request. If you don't fix the Response structure, it may not understand what comes back, but you should at least see a request sent out over the wire. You can use SoapUI to load both WSDLs and see what kind of requests are generated. The goal is to send the same request, just using document/literal instead of rpc/literal.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...