Adding a custom SOAP header using c#/ASP.NET - c#

I am trying to use a traffic web service. An example of the SOAP request is given below.
I have created a proxy class in c# using Wsdl.exe from the WSDL structure.
What I think I need to do now in somehow insert the 'authenticate' SOAP header into the SOAP structure for
the method call. I'm unsure how to add the header to the service method call?
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://www.inteleacst.com.au/wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header>
<ns1:authenticate>
<SOAP-ENC:Struct>
<username>username</username>
<password>password</password>
</SOAP-ENC:Struct>
</ns1:authenticate>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:getAllTraffic>
<States SOAP-ENC:arrayType="xsd:string[3]" xsi:type="ns1:State_Arr">
<item xsi:type="xsd:string">VIC</item>
<item xsi:type="xsd:string">NSW</item>
<item xsi:type="xsd:string">NT</item>
</States>
<EventCodes SOAP-ENC:arrayType="xsd:int[1]" xsi:type="ns1:EventCode_arr">
<item xsi:type="xsd:int">802</item>
</EventCodes>
</ns1:getAllTraffic>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Here is the code in the proxy class for calling the web service method.
[System.Web.Services.Protocols.SoapRpcMethodAttribute("http://webservice.intelecast.com.au/traffic/PublicSoap/server.php#getAllTraffic", RequestNamespace="http://webservice.intelecast.com.au/traffic/PublicSoap/server.php", ResponseNamespace="http://webservice.intelecast.com.au/traffic/PublicSoap/server.php")]
[return: System.Xml.Serialization.SoapElementAttribute("return")]
public TrafficInfo[] getAllTraffic(string[] States, int[] EventCodes) {
object[] results = this.Invoke("getAllTraffic", new object[] {
States,
EventCodes});
return ((TrafficInfo[])(results[0]));
}

Searching the web I found a forum post about a very similar problem and a good solution.
Available here - forums.asp.net/t/1137408.aspx

Adding SOAP headers is one of those things that got more convoluted with WCF compared to the previous "Add Web Service Reference" in Visual Studio .Net 2003/2005 and creating a SOAP extension.
To do it in WCF you need to add an EndPointBehavior. There are quite a few examples around, google on IEndpointBehavior and IClientMessageInspector. This article provides a nice succinct example but you may need to expand it.

Related

Service Response to WCF Includes Duplicate Namespace and Tag Prefix

Question:
Why would I receive a SOAP response fragment that contains a duplicate tag prefix namespace?
Why would I receive a different response fragment in SoapUI versus a WCF client using the exact same SOAP request?
Context:
I am calling a third-party, Java based web service with a WCF client. The SOAP fragment response sent from the third party WS contains a duplicate namespace and tag prefix for the soap envelope on the Fault tag line when calling with an incorrect value that results in a fault response. This causes the WCF to throw a CommunicationException with an innerException of XmlException which cites the following as the error:
Start element 'faultcode' from namespace '' expected. Found element 'SOAP-ENV:faultcode'
from namespace 'http://schemas.xmlsoap.org/soap/envelope/'.
This error message leads me to believe the duplicated namespace in the SOAP fragment is the culprit. The weird thing is, using the exact SOAP request sent from the WCF client to the web service in SoapUI does not result in this namespace being duplicated in the SOAP response fragment.
The WCF client is using a basicHttpBinding.
Please see below for SOAP fragments of the request, response through WCF, and response through SoapUI.
Request sent by both WCF and SoapUI:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Search xmlns="urn:ent.soap.testservice.com/objs">
<Request objType="Report">
<RequestorId>ABCD</RequestorId>
<TargetId></TargetId>
</Request>
</Search>
</s:Body>
</s:Envelope>
Response received by WCF client:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:faultcode>SOAP-ENV:Server</SOAP-ENV:faultcode>
<SOAP-ENV:faultstring>Invalid action parameters</SOAP-ENV:faultstring>
<SOAP-ENV:detail>
<fns:fault xmlns:fns="urn:fault.soap.testservice.com" xmlns:java="java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="fns:ApiFault">
<fns:exceptionCode>INTERNAL_ERROR</fns:exceptionCode>
<fns:exceptionMessage>Invalid action parameters</fns:exceptionMessage>
<fns:logDataExchangeId>1234567890</fns:logDataExchangeId>
</fns:fault>
</SOAP-ENV:detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Response received by SoapUI:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<SOAP-ENV:faultcode>SOAP-ENV:Server</SOAP-ENV:faultcode>
<SOAP-ENV:faultstring>Invalid action parameters</SOAP-ENV:faultstring>
<SOAP-ENV:detail>
<fns:fault xsi:type="fns:ApiFault" xmlns:fns="urn:fault.soap.testservice.com" xmlns:java="java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<fns:exceptionCode>INTERNAL_ERROR</fns:exceptionCode>
<fns:exceptionMessage>Invalid action parameters</fns:exceptionMessage>
<fns:logDataExchangeId>1234567890</fns:logDataExchangeId>
</fns:fault>
</SOAP-ENV:detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The problem is not the duplicated namespace declaration. The problem is in this bit:
<SOAP-ENV:faultcode>SOAP-ENV:Server</SOAP-ENV:faultcode>
<SOAP-ENV:faultstring>Invalid action parameters</SOAP-ENV:faultstring>
On the SOAP Specification, the faultcode and faultstring elements are in the empty, default namespace, not in the "http://schemas.xmlsoap.org/soap/envelope/" namespace. So it really should've looked something like this:
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:MustUnderstand</faultcode>
<faultstring>SOAP Must Understand Error</faultstring>
</SOAP-ENV:Fault>
So looks like this service in particular is not being compliant with the SOAP 1.1 (or 1.2 for that matter) specification.

Fixing a broken proxy class

I'm trying to update some WSE code to use WCF, and I'm running into trouble with one service in particular. When I generated my proxy class from the WSDL, it creates methods with no parameters or return type. The parameters were easy enough to fix -- saved the autogenerated References.cs file as a new file, added the parameter to both the generated interface and generated client, and it works. Using Fiddler, I can see that the traffic is as expected.
What I'm finding very vexing is that WCF seems to be just throwing away the response payload. I can see it coming back over the wire, but it seems to just vanish somewhere in the deep dark crevices of WCF. No errors or warnings, just gone.
I'm kind of at my wits end here. I'd really appreciate any suggestions on how to figure out where the response is going.
The method in the client (this used to return void; I've set it to object[] in hopes I could get something that I could cast):
public object[] getAddress(string user) {
return base.Channel.getAddress(user);
}
The method in the interface:
[System.ServiceModel.OperationContractAttribute(Action = "https://xxxxxx/Address#getAddress", ReplyAction = "*")]
[System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)]
object[] getAddress(string user);
The raw XML response (redacted) looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getAddressResponse xmlns="https://xxxxx/Address">
<ArrayOfAddress arrayType="xsd:Address[3]" soapenc:arrayType="xsd:anyType[3]" xsi:type="Array">
<Address>
<street xsi:type="xsd:string">3rd</street>
</Address>
<Address>
<street xsi:type="xsd:string">1st</street>
</Address>
<Address>
<street xsi:type="xsd:string">2nd</street>
</Address>
</ArrayOfAddress>
</getAddressResponse>
</soap:Body>
Thanks in advance!
EDIT: I was unable to get this resolved, and there are only a few methods on this service, so I ended up just manually interacting with the service using WebClient, bypassing WCF.
Returning object[] isn't going to give you something you can cast. WCF on the client needs to know the possible concrete types to deserialize the response. I'd expect an exception though.
To fix this you should go ahead and create the Address data contract class.

C# Parsing Response of a Java Web Service

I am calling a Java WebLogic web service from my .Net application. I have added a service reference to the jws service.
The service can be called fine and I can see the response in Fiddler, however the problem is that the propery listOfHolds is coming as null although I can see a list of holds in the XML of the response.
Here is the code for calling
holdsList result = proxy.viewHoldsList(request.AccountNo);
int noOfHolds = result.NumberOfHolds; // This value is read fine
object[] holds = result.listOfHolds; // This is coming as Null despite the values in the response
Here is the response XML as captured by Fiddler
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<work:WorkContext xmlns:work="http://oracle.com/weblogic/soap/workarea/">rO0...AAA</work:WorkContext>
</S:Header>
<S:Body>
<ns0:viewHoldsListResponse xmlns:ns0="http://www.openuri.org/">
<ns0:viewHoldsListResult>
<ns0:TotalAmount>130.0</ns0:TotalAmount>
<ns0:NumberOfHolds>4</ns0:NumberOfHolds>
<ns0:listOfHolds>
<ns0:item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns0:holdDetails">
<ns0:xsiType>HoldDetails</ns0:xsiType>
<ns0:Amount>100.0</ns0:Amount>
<ns0:StartDate>2014-02-15T00:00:00.0</ns0:StartDate>
<ns0:ExpiryDate>2014-02-20T00:00:00.0</ns0:ExpiryDate>
<ns0:Description>For testing</ns0:Description>
<ns0:Instruction/>
<ns0:Tracer>00000810000287294002</ns0:Tracer>
<ns0:HoldId>3591376655</ns0:HoldId>
<ns0:EmployeeId>0</ns0:EmployeeId>
</ns0:item>
<ns0:item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns0:holdDetails">
<ns0:xsiType>HoldDetails</ns0:xsiType>
<ns0:Amount>10.0</ns0:Amount>
<ns0:StartDate>2014-02-15T00:00:00.0</ns0:StartDate>
<ns0:ExpiryDate>2014-02-17T00:00:00.0</ns0:ExpiryDate>
<ns0:Description>DESC</ns0:Description>
<ns0:Instruction/>
<ns0:Tracer>00000810000287294004</ns0:Tracer>
<ns0:HoldId>3591376656</ns0:HoldId>
<ns0:EmployeeId>0</ns0:EmployeeId>
</ns0:item>
</ns0:listOfHolds>
</ns0:viewHoldsListResult>
</ns0:viewHoldsListResponse>
</S:Body>
</S:Envelope>
I have faced a similar problem before and the problem was a missing xmlns attribute on one of the tags. In this case I am suspecting the extra <ns0:xsiType>HoldDetails</ns0:xsiType> tag that is coming under the <ns0:item> tag.
Update Even after the web service provider removed the extra <xsiType> tag, I am unable to read the listOfHolds.
My questions are:
Can I do anything in my .Net code so that I get the intended value for listOfHolds?
Can I suggest any change to the owner of the Java web service?
[Optional] Why NumberOfHolds is being successfully read from the response but not listOfHolds?
The vendor of the web service has made a change. They changed xsi:type="ns0:holdDetails" to xsi:type="ns0:HoldDetails" (H instead of h).
The point is in Java, and unlike .Net as far as I can tell, they have a control over the generated XML from the web service.

How to create an otrs ticket using a soap request .Net

I have created a solution.
Added the WSDL file.
This keeps on popping following error "Length Required".
I tried with the above code in the post (, but seems that is not working.
Where do we specify the Operation name here?
-- Anand
Before getting it to work in java c# .net etc you need to get the SOAP xml correct.
The operation name is added as a tag in the soap body element.
Say for example your operation name is createMyOTRSTicket as specified in OTRS UI Web Service.
The SOAP request sent should look something like this like this:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<createMyOTRSTicket xmlns="WS">
<UserLogin>MyUserName</UserLogin>
<Password>MyPassword</Password>
<Queue>'some queue name'</Queue>
<State>'some state name'</State>
<Priority>1</Priority>
<!-- ...etc.. -->
<Article>
<Subject>some subject</Subject>
<Body>some body</Body>
<ContentType>text/plain; charset=utf8</ContentType>
</Article>
</createMyOTRSTicket >
</soap:Body>
</soap:Envelope>
See the API for what elements are require and which are optional for TicketCreate here
The Soap Message should be sent to /nph-genericinterface.pl/Webservice/CreateTicketWS where CreateTicketWS is the name of the Web Service.
Also note that the attribute xmlns="WS" refers to the Namespace you specify in "Network Transport" config also locatred in the GenericInterface Web Service Management.
I hope this helps you. Sorry it might be a bit confusing for someone new to SOAP and OTRS.

how to read http response soap headers from web service response in proxy class

I'm having some problems with one webservice that i'm working with. I generated a proxy class with wsdl.exe that comes with .net framework. But that webservice return a header that isnt not mapped by the wsdl. I must map the header sop because it contains some properties that i have to read and work with. how can i read the soap's header collection?
Ex.:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header xmlns="http://xml.amadeus.com/ws/2009/01/WBS_Session-2.0.xsd">
<Session>
<SessionId>545784545</SessionId>
<SequenceNumber>1</SequenceNumber>
<SecurityToken>asd7a87sda89sd45as4d5a4</SecurityToken>
</Session>
</soap:Header>
<soap:Body>
<TAM_Altea_Seguranca_AutenticarRS xmlns="http://xml.amadeus.com/2009/04/TAM/TAM_Altea_Seguranca_AutenticarRS_2.0">
<statusDoProcesso>
<codigoDoStatus>P</codigoDoStatus>
</statusDoProcesso>
</TAM_Altea_Seguranca_AutenticarRS>
</soap:Body>
</soap:Envelope>
I need to read the SOAP:HEADER -> Session.
Have you tried this?
source: Handle SOAP Headers Required by an XML Web Service Client
public class MyWebService
{
public SoapUnknownHeader[] unknownHeaders;
[WebMethod]
[SoapHeader("unknownHeaders")]
public string MyWebMethod()
{
foreach (SoapUnknownHeader header in unknownHeaders)
{
// process headers
}
// handle request
}
}
See this page for detailed instructions on defining custom SOAP headers. There only seem to be VB.net code examples, but it should be easy enough to translate the principles in C#.

Categories

Resources