Client to send SOAP request and received response

2019-01-01 01:51发布

问题:

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?

回答1:

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);
    }
}


回答2:

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();
        }
    }


回答3:

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.



回答4:

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);
       }
 }


回答5:

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.