Client zum Senden einer SOAP-Anfrage und zum Empfangen einer Antwort


159

Der Versuch, einen C # -Client zu erstellen (wird als Windows-Dienst entwickelt), der SOAP-Anforderungen an einen Webdienst sendet (und die Ergebnisse abruft).

Aus dieser Frage habe ich diesen Code gesehen:

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

Sieht gut aus, weiß jemand, wie man es benutzt und ob es die beste Vorgehensweise ist?

Antworten:


224

Normalerweise benutze ich einen anderen Weg, um dasselbe zu tun

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

1
Es ist etwas, aber ich habe alles hier platziert, einschließlich der SOAP-Anforderungszeichenfolge.
KBBWrite

5
ok, ich denke, Sie müssen das in eine SOAP-Anfrage einfügen. Wenn Sie ein Beispiel für eine Anforderungsnutzlast haben, können Sie eine Anfrage einfach so erstellen. Sie sind sich nicht sicher, welche Art von Sicherheit Sie verwenden. Wenn Sie WS-Security verwenden, können Sie den Benutzernamen und das Kennwort mit Ihrem SOAP-Anforderungsheader übergeben.
KBBWrite

3
Ich denke in so etwas wie HttpWebRequest webRequest = CreateWebRequest (_url, _action); webRequest.Credentials = new NetworkCredential (Benutzername, Passwort, Domain);
Datenbank

3
@hamish: Dies ist nur ein konzeptioneller Code-Ausschnitt. Betrachten Sie es nicht als Produktionsqualitätscode.
KBBWrite

4
Sehr hilfreich und hat mir geholfen, mit Telerik Fiddler den POST manuell an meinen Webdienst zu senden, da ich alle von Ihnen festgelegten Header sehen konnte. Vielen Dank.
Raddevus

64

Ich habe diese einfache Lösung hier :

Senden einer SOAP-Anforderung und Empfangen einer Antwort in .NET 4.0 C # ohne Verwendung der WSDL- oder Proxy-Klassen:

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

Können wir einen Seifen-XML-Client ohne Verwendung von String-Seifen-XML erstellen? Mit C # -Code. Wie folgt: var request = (HttpWebRequest) WebRequest.Create (uri); request.Method = Common.Method; Zum Beispiel eine c # -Methode, die mehr als einen Seifen-XML-Client für die verschiedenen WSDL-Dienste mit Parametern erstellt.
Dvlpr

Ich erhalte die folgende Fehlermeldung und der Code wird beendet: 'soap' ist ein nicht deklariertes Präfix. Zeile 2, Position 18. Vermisse ich etwas? Die SOAP-UI-Anfrage für meinen Webservice finden Sie hier: stackoverflow.com/questions/50430398/…
Vesnog

Funktioniert mit webRequest.Headers.Add("SOAPAction", "http://tempuri.org/.....");Überprüfen Sie die SOAP-Aktion in SoapUI und verwenden Sie diese.
Robert Koch

Ich erhalte eine Fehlermeldung, wenn ich den Doppelpunkt im SOAPAction-Header verwende. Ich muss tun: webRequest.Headers.Add (@ "SOAPAction", "SomeAction");
Entwickler Webs

Wie empfangen und in PDF umwandeln?
Leandro

20

Die beste Vorgehensweise besteht darin, auf die WSDL zu verweisen und sie wie eine Webdienstreferenz zu verwenden. Es ist einfacher und funktioniert besser, aber wenn Sie nicht über die WSDL verfügen, sind die XSD-Definitionen ein guter Code.


1
Wie kann ich einen benutzerdefinierten Header für SOAP-Anforderungen hinzufügen, wenn ich WSDL als Webdienstreferenz und auch als Endpunkte hinzufüge?
BASEER HAIDER JAFRI

12
Sie erwähnen, dies zu tun, einen Hinweis darauf, wie dies zu tun ist?
Zapnologica

Wenn die WSDL keinen benutzerdefinierten Header möchte, sollten Sie keinen hinzufügen.
StingyJack

1
Was wird grundsätzlich zum Senden und Empfangen von SOAP benötigt? Reicht es aus, eine Bindung zu verwenden, die SOAP wie wsHttpBinding und Referenz-WSDL unterstützt? Alles andere ist dasselbe wie die Verwendung von REST (Aufrufen von WCF-Methoden, Empfangen einer Antwort)?
FrenkyB

Ich stimmte den WSDLs zu, die erstere ist viel komplexer und unnötiger. Sie müssen lediglich in Ihrem Projekt auf Dienstreferenzen zugreifen (in älteren Versionen von Visual Studio), mit der rechten Maustaste klicken, Dienstreferenz hinzufügen und die richtigen Details eingeben. Es wird ein c # -Objekt erstellt, das als Variable erstellt werden muss. Alle Funktionen des WSDL-Dienstes werden dann durch Code verfügbar gemacht
lllllllllllllIllllIll

19

Ich denke, es gibt einen einfacheren Weg:

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

Das hat wie ein Champion funktioniert. Ich habe der CreateSoapEnvelope-Methode Parameter hinzugefügt, um die Zeichenfolge XML, die Post-URL und die Aktions-URL übergeben zu können, damit die Methoden wiederverwendbar sind, und es war genau das, wonach ich gesucht habe.
Slippery Pete

Beste Antwort für meine Meinung, weil es relevanteren HttpClient anstelle von veralteter WebResponse verwendet.
Akmal Salikhov

15

Ich habe eine allgemeinere Hilfsklasse geschrieben, die ein auf Zeichenfolgen basierendes Wörterbuch mit benutzerdefinierten Parametern akzeptiert, damit diese vom Aufrufer festgelegt werden können, ohne sie fest codieren zu müssen. Es versteht sich von selbst, dass Sie eine solche Methode nur verwenden sollten, wenn Sie einen SOAP-basierten Webdienst manuell ausgeben möchten (oder müssen): In den meisten gängigen Szenarien wird empfohlen, die Webdienst-WSDL zusammen mit der Add Service Reference Visual Studio zu verwenden Funktion stattdessen.

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

Für weitere Informationen und Details zu dieser Klasse können Sie diesen Beitrag auch in meinem Blog lesen .


1

Dies ist also mein endgültiger Code, nachdem ich 2 Tage lang gegoogelt habe, wie man einen Namespace hinzufügt und zusammen mit dem SOAP-Umschlag eine Seifenanforderung stellt, ohne Proxy / Servicereferenz hinzuzufügen

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

-5

Rufen Sie den SOAP-Webservice in c # auf

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

3
Was ist new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient()?
Chris F Carroll
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.