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?
However, 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();
}
}
The best practice is to reference the WSDL and use it like a web service reference.
Easier and works fine, but if you don\'t have the WSDL or the XSD definitions is a good pice of code.
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);
}
}
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.