I have the following program written in C# to consume a web service.
class Program
{
static void Main(string[] args)
{
Program obj = new Program();
obj.InvokeService();
}
public HttpWebRequest CreateSOAPWebRequest()
{
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create(#"https://MyWebService");
Req.ContentType = "text/xml;charset=\"utf-8\"";
Req.Accept = "text/xml";
Req.Method = "POST";
return Req;
}
public void InvokeService()
{
HttpWebRequest request = CreateSOAPWebRequest();
XmlDocument SOAPReqBody = new XmlDocument();
SOAPReqBody.LoadXml(#"<?xml version=""1.0"" encoding=""utf-8""?>
<soapenv:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-
instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:soapenc=""http://schemas.xmlsoap.org/soap/encoding/"">
<soapenv:Header/>
<soapenv:Body>
<Content>..... </Content>
</soapenv:Body>
</soapenv:Envelope>");
using (Stream stream = request.GetRequestStream())
{
SOAPReqBody.Save(stream);
}
using (WebResponse Serviceres = request.GetResponse())
{
using (StreamReader rd = new
StreamReader(Serviceres.GetResponseStream()))
{
var ServiceResult = rd.ReadToEnd();
Console.WriteLine(ServiceResult);
Console.ReadLine();
}
}
}
}
I now want to attach the WSDL to this soap request.
What I have is a .wsdl file. I tried this SOAP request using "SOAP UI" and it worked , I received the response.
It seems like I need to specify the method in the SOAP header and I am not able to do that. I can only place the .WSDL file somewhere in the project folder.
Can someone help me to get the correct response ?
Related
I have a VBA code which calls a SOAP service and receives an XML response.
I want to write a C# REST API to call this SOAP service in a similar way.
Referring to the articles here I wrote a SOAP request but it does not works and returns the below error. I am able to call this SOAP service from the VBA code and also POST MAN. Can some one please explain what's wrong with my code?
public class CallSOAPAPIController : ApiController
{
[HttpGet]
public string Extract()
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(#"<?xml version=""1.0"" encoding=""utf-8""?><soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:inc=""http://www.test-xyz.com/""><soap:Body>Calendar #Year#Month#1</soap:Body></soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
return soapResult;
}
/// <summary>
/// Create a soap webrequest to [Url]
/// </summary>
/// <returns></returns>
public static HttpWebRequest CreateWebRequest()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(#"http://test.production-xyz.com/listofemployees.do?getdetails=all&SOAP");
webRequest.Headers.Add(#"SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
CallSOAPAPIController obj = new CallSOAPAPIController();
string base64Credentials = obj.GetEncodedCredentials();
webRequest.Headers.Add("Authorization", "Basic " + base64Credentials);
return webRequest;
}
private string GetEncodedCredentials()
{
string m_Username = "XXXXXX";
string m_Password = "XXXXXX";
string mergedCredentials = string.Format("{0}:{1}", m_Username, m_Password);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
return Convert.ToBase64String(byteCredentials);
}
}
The error I get : "The remote server returned an error:(401) Unauthorized"
Unauthorized(401)
C# Code:
public static void CallWebService(string XmlText)
{
try
{
var _url = "https://nodeD1.test.webservices.amadeus.com/1ASIWMLFPNP";// "https://noded1.test.webservices.amadeus.com/1asiwmlfpnp";
var _action = "http://webservices.amadeus.com/fmptbq_14_3_1a";
XmlDocument soapEnvelopeXml = CreateSoapEnvelope(XmlText);
HttpWebRequest webRequest = CreateWebRequest(_url, _action);
webRequest = InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
// begin async call to web request.
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI.
asyncResult.AsyncWaitHandle.WaitOne();
// get the response from the completed web request.
string soapResult;
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
Console.Write(soapResult);
}
}
catch (WebException webex)
{
WebResponse errResp = webex.Response;
using (Stream respStream = errResp.GetResponseStream())
{
StreamReader reader = new StreamReader(respStream);
string text = reader.ReadToEnd();
}
}
}
private static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static XmlDocument CreateSoapEnvelope(string XmlText)
{
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(string.Format(#"{0}",XmlText));
return soapEnvelopeDocument;
}
private static HttpWebRequest InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
return webRequest;
}
}
Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://xml.amadeus.com/2010/06/Security_v1" xmlns:typ="http://xml.amadeus.com/2010/06/Types_v1" xmlns:iat="http://www.iata.org/IATA/2007/00/IATA2010.1" xmlns:app="http://xml.amadeus.com/2010/06/AppMdw_CommonTypes_v3" xmlns:link="http://wsdl.amadeus.com/2010/06/ws/Link_v1" xmlns:ses="http://xml.amadeus.com/2010/06/Session_v3" xmlns:fmp="http://xml.amadeus.com/FMPTBQ_14_3_1A">
<soapenv:Header>
<add:MessageID xmlns:add="http://www.w3.org/2005/08/addressing">29e8e874-3033-dd52-6b75-a2da58e10291</add:MessageID>
<add:Action xmlns:add="http://www.w3.org/2005/08/addressing">http://webservices.amadeus.com/fmptbq_14_3_1A</add:Action>
<add:To xmlns:add="http://www.w3.org/2005/08/addressing">https://noded1.test.webservices.amadeus.com/1asiwmlfpnp</add:To>
<link:TransactionFlowLink xmlns:link="http://wsdl.amadeus.com/2010/06/ws/Link_v1"/>
<oas:Security xmlns:oas="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<oas:UsernameToken oas1:Id="UsernameToken-1" xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<oas:Username>WSPNPMLF</oas:Username>
<oas:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bTEzbk5LNElzZw==</oas:Nonce>
<oas:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">5lkky7mUVRujQPg4blzfKi5dSyg=</oas:Password>
<oas1:Created>2017-12-15T13:43:34:532Z</oas1:Created>
</oas:UsernameToken>
</oas:Security>
<AMA_SecurityHostedUser xmlns="http://xml.amadeus.com/2010/06/Security_v1">
<UserID AgentDutyCode="SU" POS_Type="1" PseudoCityCode="BLRVS32CY" RequestorType="U"/>
</AMA_SecurityHostedUser>
</soapenv:Header>
<soapenv:Body>
<Fare_MasterPricerTravelBoardSearch>
<numberOfUnit>
<unitNumberDetail>
<numberOfUnits>1</numberOfUnits>
<typeOfUnit>PX</typeOfUnit>
</unitNumberDetail>
<unitNumberDetail>
<numberOfUnits>250</numberOfUnits>
<typeOfUnit>RC</typeOfUnit>
</unitNumberDetail>
</numberOfUnit>
<paxReference>
<ptc>ADT</ptc>
<traveller>
<ref>1</ref>
</traveller>
</paxReference>
<fareOptions>
<pricingTickInfo>
<pricingTicketing>
<priceType>RP</priceType>
<priceType>RU</priceType>
<priceType>TAC</priceType>
<priceType>ET</priceType>
</pricingTicketing>
</pricingTickInfo>
</fareOptions>
<travelFlightInfo>
<cabinId>
<cabinQualifier>RC</cabinQualifier>
<cabin>Y</cabin>
</cabinId>
</travelFlightInfo>
<itinerary>
<requestedSegmentRef>
<segRef>1</segRef>
</requestedSegmentRef>
<departureLocalization>
<depMultiCity>
<locationId>DEL</locationId>
</depMultiCity>
</departureLocalization>
<arrivalLocalization>
<arrivalMultiCity>
<locationId>BOM</locationId>
</arrivalMultiCity>
</arrivalLocalization>
<timeDetails>
<firstDateTimeDetail>
<timeQualifier>TD</timeQualifier>
<date>201217</date>
<time>0000</time>
<timeWindow></timeWindow>
</firstDateTimeDetail>
</timeDetails>
</itinerary>
<itinerary>
<requestedSegmentRef>
<segRef>1</segRef>
</requestedSegmentRef>
<departureLocalization>
<depMultiCity>
<locationId>BOM</locationId>
</depMultiCity>
</departureLocalization>
<arrivalLocalization>
<arrivalMultiCity>
<locationId>DEL</locationId>
</arrivalMultiCity>
</arrivalLocalization>
<timeDetails>
<firstDateTimeDetail>
<timeQualifier>TD</timeQualifier>
<date>251217</date>
<time>0000</time>
<timeWindow></timeWindow>
</firstDateTimeDetail>
</timeDetails>
</itinerary>
</Fare_MasterPricerTravelBoardSearch>
</soapenv:Body>
</soapenv:Envelope>
Response:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>12|Presentation|soap message header incorrect</faultstring>
<faultactor>SI:muxDZ2</faultactor>
</soap:Fault>
</soap:Body>
</soap:Envelope>
When the same request is passed using SoapUI im getting response but when C# Code is used im getting the above response.. if any one have implemented Amadeus Soap4.0 API in C# please help.
Maybe you have setup SoapUI to perform additional actions on the request payload (thus the request is not the same) ?
I would advise to create a proxy class from the given WSDL. While this proxy class doesn't support Nonce by default, it's extensible. check out WCF: Adding Nonce to UsernameToken
Now the 12 error code you get could also derive from other things.... Like for example I don't see your <Session /> element there (unless this represents a stateless request?)
I am just learning how to send SOAP requests to my AVM FritzBox 7270 router using C#.
Here ist my method that sends a SOAP request to the router:
private string Execute(string controlUrl, string serviceType, string action)
{
WebRequest webRequest = WebRequest.Create("http://fritz.box:49000" + controlUrl);
HttpWebRequest httpRequest = (HttpWebRequest)webRequest;
httpRequest.Method = "POST";
httpRequest.ContentType = "text/xml; charset=utf-8";
httpRequest.Headers.Add("SOAPACTION", string.Format("{0}#{1}", serviceType, action));
httpRequest.ProtocolVersion = HttpVersion.Version11;
httpRequest.Credentials = new NetworkCredential("username", "password");
Stream requestStream = httpRequest.GetRequestStream();
StreamWriter streamWriter = new StreamWriter(requestStream, Encoding.ASCII);
streamWriter.Write(GetBody(serviceType, action));
streamWriter.Close();
//Get the Response
try
{
HttpWebResponse wr = (HttpWebResponse)httpRequest.GetResponse();
StreamReader srd = new StreamReader(wr.GetResponseStream());
return srd.ReadToEnd();
}
catch (WebException)
{
return null;
}
}
Function GetBody:
private string GetBody(string serviceType, string action)
{
const string fmt = #"<?xml version=""1.0"" encoding=""utf-8""?>
<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"" s:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/"">
<s:Body>
<u:{0} xmlns:u=""{1}"" />
</s:Body>
</s:Envelope>
";
return string.Format(fmt, action, serviceType);
}
}
I tested this method with parameters that I found anywhere in the internet:
controlUrl = "/upnp/control/WANIPConn1"
serviceType = "urn:schemas-upnp-org:service:WANIPConnection:1"
action = "GetExternalIPAddress"
This works well.
However, I think I should go the official way and first send a request
http://fritz.box:49000/tr64desc.xml
to receive parameters valid for my actual router. In the response to this request I find the following node:
<service>
<serviceType>urn:dslforum-org:service:WANIPConnection:1</serviceType>
<serviceId>urn:WANIPConnection-com:serviceId:WANIPConnection1</serviceId>
<controlURL>/upnp/control/wanipconnection1</controlURL>
<eventSubURL>/upnp/control/wanipconnection1</eventSubURL>
<SCPDURL>/wanipconnSCPD.xml</SCPDURL>
</service>
Using these values for serviceId and controlUrl, I get error 500 (Internal Server Error).
Who can help me? What is wrong in my code?
I think the problem is solved:
There seem to be a lot of undocumeted features of the Fritz.Box, and the pararmeters I found in the internet oviously are part of thease features.
With
<service>
<serviceType>urn:dslforum-org:service:WANPPPConnection:1</serviceType>
<serviceId>urn:WANPPPConnection-com:serviceId:WANPPPConnection1</serviceId>
<controlURL>/upnp/control/wanpppconn1</controlURL>
<eventSubURL>/upnp/control/wanpppconn1</eventSubURL>
<SCPDURL>/wanpppconnSCPD.xml</SCPDURL>
</service>
I can call
GetExternalIPAddress
without problems.
I need help with wrapping an XML in a SOAP envelope for a third party SOAP server. The third party has provided xsd files for the inbound request and outbound response. I've taken those XSD files and created C# classes of them using the xsd tool. My problem is that I need to wrap the serialized request with a SOAP envelope and I don't know where to start. I was looking at the Microsoft Web Service Enhancements 3, but that says that it's only for .net 2.0 and VS2005. I am using VS2012 and .net 4.5. Also, I've looked into connecting to the server by way of web service but it doesn't seem compatible and does not have a WSDL.
The following is a sample of what the SOAP server expects for an inbound request.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body>
<GetBasicData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="CRS610MI">
<CONO xmlns="">1</CONO>
<CUNO xmlns="">12345</CUNO>
</GetBasicData>
</soap:Body>
</soap:Envelope>
This is what the serialized XML string looks like.
<?xml version="1.0" encoding="utf-8"?>
<GetBasicData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="CRS610MI">
<CONO xmlns="">1</CONO>
<CUNO xmlns="">12345</CUNO>
</GetBasicData>
Code I'm using for my web request and response.
Byte[] byteArray = System.Text.UTF8Encoding.UTF8.GetBytes(data);
WebRequest webRequest = WebRequest.Create(#"http://myserver:8888");
webRequest.ContentLength = byteArray.Length;
webRequest.ContentType = #"text/xml; charset=utf-8";
webRequest.Headers.Add("SOAPAction", #"http://schemas.xmlsoap.org/soap/envelope/");
webRequest.Method = "POST";
Stream requestStream = webRequest.GetRequestStream();
requestStream.Write(byteArray, 0, byteArray.Length);
requestStream.Close();
requestStream.Dispose();
WebResponse webResponse = webRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream);
String line;
while ((line = streamReader.ReadLine()) != null)
{
Debug.WriteLine(line);
}
I've tested my code by replacing my serialized string with the text in the sample file provided by the third party and it worked as expected. I also took my serialized string and inserted the envelope text in the correct places and that also worked, web request went through and I got the response I was looking for. Short of inserting the envelope text into my serialized string manually what can I do. I have to imagine there's a method or class that will take care of this for me in a standardized way?
I was able to solve this by using an XLST to wrap the XML in soap.
Here's my working test app code
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Xml.Xsl;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
GetBasicData getBasicData = new GetBasicData();
getBasicData.CONO = "1";
getBasicData.CUNO = "201702";
XPathDocument requestXPathDocument;
if (SerializeIntoRequestXPathDocument(getBasicData, out requestXPathDocument))
{
XmlDocument requestXmlDocument;
if (CreateRequestXMLDocument(requestXPathDocument, #"Z:\Darice\M3 SOAP\GetBasicData.xsl", out requestXmlDocument))
{
XmlDocument responseXmlDocument;
if (ExecuteRequestSoap(requestXmlDocument, out responseXmlDocument))
{
MemoryStream unwrappedMemoryStream;
if (UnwrapSoapResponseXmlDocumentIntoMemoryStream(responseXmlDocument, out unwrappedMemoryStream))
{
GetBasicDataResponse getBasicDataResponse;
if (!DeserializeResponseMemoryStream(unwrappedMemoryStream, out getBasicDataResponse))
{
Debug.WriteLine("FAIL");
}
}
}
}
}
Console.ReadLine();
}
//STATIC FUNCTIONS
private static Boolean CreateRequestXMLDocument(XPathDocument xPathDocument, String xslPath, out XmlDocument xmlDocument)
{
try
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (StreamWriter streamWriter = new StreamWriter(memoryStream))
{
XmlWriter xmlWriter = XmlWriter.Create(streamWriter);
XsltSettings xsltSettings = new XsltSettings();
xsltSettings.EnableScript = true;
XslCompiledTransform xslCompiledTransform = new XslCompiledTransform();
xslCompiledTransform.Load(xslPath, xsltSettings, null);
xslCompiledTransform.Transform(xPathDocument, xmlWriter);
memoryStream.Position = 0;
using (StreamReader streamReader = new StreamReader(memoryStream))
{
XmlReader xmlReader = XmlReader.Create(streamReader);
xmlDocument = new XmlDocument();
xmlDocument.Load(xmlReader);
}
}
}
}
catch (Exception exception)
{
Debug.WriteLine(exception);
xmlDocument = null;
return false;
}
return true;
}
private static Boolean DeserializeResponseMemoryStream<T>(MemoryStream memoryStream, out T xmlObject)
{
try
{
using (StreamReader streamReader = new StreamReader(memoryStream))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (XmlReader xmlReader = XmlReader.Create(streamReader))
{
xmlObject = (T)xmlSerializer.Deserialize(xmlReader);
}
}
}
catch (Exception exception)
{
Debug.WriteLine(exception);
xmlObject = default(T);
return false;
}
return true;
}
private static Boolean ExecuteRequestSoap(XmlDocument requestXmlDocument, out XmlDocument responseXmlDocument)
{
try
{
Byte[] byteArray = UTF8Encoding.UTF8.GetBytes(requestXmlDocument.OuterXml);
WebRequest webRequest = WebRequest.Create(Properties.Resources.SoapServerAddress);
webRequest.ContentLength = byteArray.Length;
webRequest.ContentType = #"text/xml; charset=utf-8";
webRequest.Headers.Add("SOAPAction", #"http://schemas.xmlsoap.org/soap/envelope/");
webRequest.Method = "POST";
using (Stream requestStream = webRequest.GetRequestStream())
{
requestStream.Write(byteArray, 0, byteArray.Length);
using (WebResponse webResponse = webRequest.GetResponse())
{
using (Stream responseStream = webResponse.GetResponseStream())
{
using (StreamReader streamReader = new StreamReader(responseStream))
{
responseXmlDocument = new XmlDocument();
responseXmlDocument.LoadXml(streamReader.ReadToEnd());
}
}
}
}
}
catch (Exception exception)
{
Debug.WriteLine(exception);
responseXmlDocument = null;
return false;
}
return true;
}
private static Boolean SerializeIntoRequestXPathDocument<T>(T dataObject, out XPathDocument xPathDocument)
{
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream())
{
using (StreamWriter streamWriter = new StreamWriter(memoryStream))
{
xmlSerializer.Serialize(streamWriter, dataObject);
memoryStream.Position = 0;
using (StreamReader streamReader = new StreamReader(memoryStream))
{
memoryStream.Position = 0;
xPathDocument = new XPathDocument(streamReader);
}
}
}
}
catch (Exception exception)
{
Debug.WriteLine(exception);
xPathDocument = null;
return false;
}
return true;
}
private static Boolean UnwrapSoapResponseXmlDocumentIntoMemoryStream(XmlDocument responseXmlDocument, out MemoryStream memoryStream)
{
try
{
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(responseXmlDocument.NameTable);
xmlNamespaceManager.AddNamespace("tns", "CRS610MI");
xmlNamespaceManager.AddNamespace("SOAP", #"http://schemas.xmlsoap.org/soap/envelope/");
XmlNode xmlNode = responseXmlDocument.SelectSingleNode(#"/SOAP:Envelope/SOAP:Body/tns:GetBasicDataResponse", xmlNamespaceManager);
memoryStream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(xmlNode.OuterXml));
}
catch (Exception exception)
{
Debug.WriteLine(exception);
memoryStream = null;
return false;
}
return true;
}
}
}
And here's the XSL code
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:crs="CRS610MI" exclude-result-prefixes="crs">
<xsl:output method="xml"/>
<xsl:template match="/">
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body>
<xsl:apply-templates select="node()|#*"/>
</soap:Body>
</soap:Envelope>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If the service provider does not provide a WSDL, then you should not do business with them. It's not rocket science, and it is the standard way that SOAP web services work. It's only been a standard for over a decade. I would seriously wonder in what other way this service provider is incompetent.
If you have no choice but to do business with incompetent business partners, then
Good luck to you
Create your own WSDL to match their service, then use "Add Service Reference" to create the proxy classes necessary to communicate to the service.
You need to mark your class with MessageContract for soap
[MessageContract]
public class ExampleResponse
{
private string _myResponse = String.Empty;
[MessageBodyMember(Name = "ResponseToGive", Namespace = "http://myserver:8888")]
public string ResponseToGive
{
get { return _myResponse; }
set { _myResponse = value; }
}
}
I don’t understand why some are so resolute that you HAVE to use the WSDL. The WSDL is simply so that you can call their methods, and use their entities, and is optional.
I’ve gotten this to work by going to the exact url for their service, such as
https://something.com/SomeService/TheService.asmx?method=DoSomething
And just analyzing the exact header and XML their API defines, including the SOAP envelope. The first section should be the header information, and then below that is the XML. Create the XML exactly how they specify, including the envelope tags. For the Header: POST, Host, Content-Type and SOAPAction, are the most important. I’ve found that some servers don’t need Content-Length, even though its listed in their API.
Here is some sample code
public void PostXMLData(string serviceUrl, XDocument requestXML)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(serviceUrl);
req.Method = "POST";
req.Host = "SOMETHING";
req.ContentType = "text/xml; charset=utf-8";
req.Headers.Add("SOAPAction", "SOMETHING");
req.Accept = "text/xml";
using (Stream stream = req.GetRequestStream())
{
requestXML.Save(stream);
}
using (WebResponse resp = req.GetResponse())
{
using (StreamReader rd = new StreamReader(resp.GetResponseStream()))
{
var result = rd.ReadToEnd();
if (result.Contains("error"))
{
throw new Exception($"XML Submission Failed: {result}");
}
}
}
}
Trying to create a C# client (will be developed as a Windows service) that sends SOAP requests to a web service (and gets the results).
From this question I saw this code:
protected virtual WebRequest CreateRequest(ISoapMessage soapMessage)
{
var wr = WebRequest.Create(soapMessage.Uri);
wr.ContentType = "text/xml;charset=utf-8";
wr.ContentLength = soapMessage.ContentXml.Length;
wr.Headers.Add("SOAPAction", soapMessage.SoapAction);
wr.Credentials = soapMessage.Credentials;
wr.Method = "POST";
wr.GetRequestStream().Write(Encoding.UTF8.GetBytes(soapMessage.ContentXml), 0, soapMessage.ContentXml.Length);
return wr;
}
public interface ISoapMessage
{
string Uri { get; }
string ContentXml { get; }
string SoapAction { get; }
ICredentials Credentials { get; }
}
Looks nice, anyone knows how to use it and if it is the best practice?
I normally use another way to do the same
using System.Xml;
using System.Net;
using System.IO;
public static void CallWebService()
{
var _url = "http://xxxxxxxxx/Service1.asmx";
var _action = "http://xxxxxxxx/Service1.asmx?op=HelloWorld";
XmlDocument soapEnvelopeXml = CreateSoapEnvelope();
HttpWebRequest webRequest = CreateWebRequest(_url, _action);
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
// begin async call to web request.
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI.
asyncResult.AsyncWaitHandle.WaitOne();
// get the response from the completed web request.
string soapResult;
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
Console.Write(soapResult);
}
}
private static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static XmlDocument CreateSoapEnvelope()
{
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(
#"<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:xsi=""http://www.w3.org/1999/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/1999/XMLSchema"">
<SOAP-ENV:Body>
<HelloWorld xmlns=""http://tempuri.org/""
SOAP-ENV:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/"">
<int1 xsi:type=""xsd:integer"">12</int1>
<int2 xsi:type=""xsd:integer"">32</int2>
</HelloWorld>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>");
return soapEnvelopeDocument;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}
I got this simple solution here:
Sending SOAP request and receiving response in .NET 4.0 C# without using the WSDL or proxy classes:
class Program
{
/// <summary>
/// Execute a Soap WebService call
/// </summary>
public static void Execute()
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(#"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
<soap:Body>
<HelloWorld xmlns=""http://tempuri.org/"" />
</soap:Body>
</soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
/// <summary>
/// Create a soap webrequest to [Url]
/// </summary>
/// <returns></returns>
public static HttpWebRequest CreateWebRequest()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(#"http://localhost:56405/WebService1.asmx?op=HelloWorld");
webRequest.Headers.Add(#"SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
static void Main(string[] args)
{
Execute();
}
}
I think there is a simpler way:
public async Task<string> CreateSoapEnvelope()
{
string soapString = #"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
<soap:Body>
<HelloWorld xmlns=""http://tempuri.org/"" />
</soap:Body>
</soap:Envelope>";
HttpResponseMessage response = await PostXmlRequest("your_url_here", soapString);
string content = await response.Content.ReadAsStringAsync();
return content;
}
public static async Task<HttpResponseMessage> PostXmlRequest(string baseUrl, string xmlString)
{
using (var httpClient = new HttpClient())
{
var httpContent = new StringContent(xmlString, Encoding.UTF8, "text/xml");
httpContent.Headers.Add("SOAPAction", "http://tempuri.org/HelloWorld");
return await httpClient.PostAsync(baseUrl, httpContent);
}
}
The best practice is to reference the WSDL and use it like a web service reference.
It's easier and works better, but if you don't have the WSDL, the XSD definitions are a good piece of code.
I wrote a more general helper class which accepts a string-based dictionary of custom parameters, so that they can be set by the caller without having to hard-code them. It goes without saying that you should only use such method when you want (or need) to manually issue a SOAP-based web service: in most common scenarios the recommended approach would be using the Web Service WSDL together with the Add Service Reference Visual Studio feature instead.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml;
namespace Ryadel.Web.SOAP
{
/// <summary>
/// Helper class to send custom SOAP requests.
/// </summary>
public static class SOAPHelper
{
/// <summary>
/// Sends a custom sync SOAP request to given URL and receive a request
/// </summary>
/// <param name="url">The WebService endpoint URL</param>
/// <param name="action">The WebService action name</param>
/// <param name="parameters">A dictionary containing the parameters in a key-value fashion</param>
/// <param name="soapAction">The SOAPAction value, as specified in the Web Service's WSDL (or NULL to use the url parameter)</param>
/// <param name="useSOAP12">Set this to TRUE to use the SOAP v1.2 protocol, FALSE to use the SOAP v1.1 (default)</param>
/// <returns>A string containing the raw Web Service response</returns>
public static string SendSOAPRequest(string url, string action, Dictionary<string, string> parameters, string soapAction = null, bool useSOAP12 = false)
{
// Create the SOAP envelope
XmlDocument soapEnvelopeXml = new XmlDocument();
var xmlStr = (useSOAP12)
? #"<?xml version=""1.0"" encoding=""utf-8""?>
<soap12:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soap12=""http://www.w3.org/2003/05/soap-envelope"">
<soap12:Body>
<{0} xmlns=""{1}"">{2}</{0}>
</soap12:Body>
</soap12:Envelope>"
: #"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<soap:Body>
<{0} xmlns=""{1}"">{2}</{0}>
</soap:Body>
</soap:Envelope>";
string parms = string.Join(string.Empty, parameters.Select(kv => String.Format("<{0}>{1}</{0}>", kv.Key, kv.Value)).ToArray());
var s = String.Format(xmlStr, action, new Uri(url).GetLeftPart(UriPartial.Authority) + "/", parms);
soapEnvelopeXml.LoadXml(s);
// Create the web request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", soapAction ?? url);
webRequest.ContentType = (useSOAP12) ? "application/soap+xml;charset=\"utf-8\"" : "text/xml;charset=\"utf-8\"";
webRequest.Accept = (useSOAP12) ? "application/soap+xml" : "text/xml";
webRequest.Method = "POST";
// Insert SOAP envelope
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
// Send request and retrieve result
string result;
using (WebResponse response = webRequest.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
result = rd.ReadToEnd();
}
}
return result;
}
}
}
For additional info & details regarding this class you can also read this post on my blog.
So this is my final code after googling for 2 days on how to add a namespace and make soap request along with the SOAP envelope without adding proxy/Service Reference
class Request
{
public static void Execute(string XML)
{
try
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(AppendEnvelope(AddNamespace(XML)));
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static HttpWebRequest CreateWebRequest()
{
string ICMURL = System.Configuration.ConfigurationManager.AppSettings.Get("ICMUrl");
HttpWebRequest webRequest = null;
try
{
webRequest = (HttpWebRequest)WebRequest.Create(ICMURL);
webRequest.Headers.Add(#"SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return webRequest;
}
private static string AddNamespace(string XML)
{
string result = string.Empty;
try
{
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(XML);
XmlElement temproot = xdoc.CreateElement("ws", "Request", "http://example.com/");
temproot.InnerXml = xdoc.DocumentElement.InnerXml;
result = temproot.OuterXml;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return result;
}
private static string AppendEnvelope(string data)
{
string head= #"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" ><soapenv:Header/><soapenv:Body>";
string end = #"</soapenv:Body></soapenv:Envelope>";
return head + data + end;
}
}
As an alternative, and pretty close to debiasej approach. Since a SOAP request is just a HTTP request, you can simply perform a GET or POST using with HTTP client, but it's not mandatory to build SOAP envelope.
Something like this:
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace HGF.Infraestructure.Communications
{
public class SOAPSample
{
private readonly IHttpClientFactory _clientFactory;
private readonly ILogger<DocumentProvider> _logger;
public SOAPSample(ILogger<DocumentProvider> logger,
IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
_logger = logger;
}
public async Task<string> UsingGet(int value1, int value2)
{
try
{
var client = _clientFactory.CreateClient();
var response = await client.GetAsync($"https://hostname.com/webservice.asmx/SampleMethod?value1={value1}&value2={value2}", HttpCompletionOption.ResponseHeadersRead);
//NULL check, HTTP Status Check....
return await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Oops! Something went wrong");
return ex.Message;
}
}
public async Task<string> UsingPost(int value1, int value2)
{
try
{
var content = new StringContent($"value1={value1}&value2={value2}", Encoding.UTF8, "application/x-www-form-urlencoded");
var client = _clientFactory.CreateClient();
var response = await client.PostAsync("https://hostname.com/webservice.asmx/SampleMethod", content);
//NULL check, HTTP Status Check....
return await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Oops! Something went wrong");
return ex.Message;
}
}
}
}
Of course, it depends on your scenario. If the payload is too complex, then this won't work
Call SOAP webservice in c#
using (var client = new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient("OutlookServiceSoap"))
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
var result = client.UploadAttachmentBase64(GUID, FinalFileName, fileURL);
if (result == true)
{
resultFlag = true;
}
else
{
resultFlag = false;
}
LogWriter.LogWrite1("resultFlag : " + resultFlag);
}