Klient wysyła żądanie SOAP i odbiera odpowiedź


159

Próba stworzenia klienta C # (zostanie opracowany jako usługa Windows), który wysyła żądania SOAP do usługi internetowej (i pobiera wyniki).

Z tego pytania widziałem ten kod:

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

Wygląda ładnie, ktoś wie, jak go używać i czy to najlepsza praktyka?

Odpowiedzi:


224

Zwykle używam innego sposobu, aby zrobić to samo

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
To jest to samo, ale umieściłem tutaj wszystko, w tym ciąg żądania SOAP.
KBBWrite

5
ok, myślę, że musisz to umieścić w żądaniu SOAP, jeśli masz próbkę ładunku żądania, możesz tak po prostu zbudować żądanie. Nie jestem pewien, jakiego rodzaju zabezpieczeń używasz. Jeśli używasz WS-Security, to nazwa użytkownika i hasło, które możesz przekazać w nagłówku żądania SOAP.
KBBWrite

3
Myślę w czymś takim HttpWebRequest webRequest = CreateWebRequest (_url, _action); webRequest.Credentials = new NetworkCredential (nazwa użytkownika, hasło, domena);
Data-Base

3
@hamish: to tylko fragment kodu koncepcyjnego. Nie traktuj tego jako kodu jakości produkcji.
KBBWrite

4
Niezwykle pomocny i pomógł mi w pracy przy użyciu Telerik Fiddler do ręcznego POST w mojej usłudze internetowej, ponieważ mogłem zobaczyć wszystkie ustawione przez Ciebie nagłówki. Dziękuję bardzo.
raddevus

64

Mam tutaj to proste rozwiązanie :

Wysyłanie żądania SOAP i odbieranie odpowiedzi w .NET 4.0 C # bez użycia klas WSDL lub proxy:

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

Czy możemy stworzyć klienta mydła xml bez użycia string soap xml. Za pomocą kodu w języku C #. Tak jak: var request = (HttpWebRequest) WebRequest.Create (uri); request.Method = Common.Method; Na przykład jedna metoda C #, która tworzy więcej niż jednego klienta mydła XML do różnych usług WSDL z parametrami.
Dvlpr

Otrzymuję następujący błąd i kod się kończy: „mydło” to niezadeklarowany prefiks. Wiersz 2, pozycja 18. Czy coś mi brakuje? Żądanie interfejsu SOAP dla mojej usługi internetowej można znaleźć tutaj: stackoverflow.com/questions/50430398/ ...
Vesnog

Działa z webRequest.Headers.Add("SOAPAction", "http://tempuri.org/.....");Check the SOAP Action w SoapUI i użyj tego.
Robert Koch

Gdy używam dwukropka w nagłówku SOAPAction, pojawia się błąd. Muszę zrobić: webRequest.Headers.Add (@ "SOAPAction", "SomeAction");
Strony internetowe deweloperów

jak otrzymany plik i przekształcić w PDF?
Leandro

20

Najlepszą praktyką jest odwoływanie się do WSDL i używanie go jako odwołania do usługi WWW. Jest to łatwiejsze i działa lepiej, ale jeśli nie masz WSDL, definicje XSD są dobrym fragmentem kodu.


1
Jak mogę dodać niestandardowy nagłówek dla żądania SOAP Jeśli dodam WSDL jako odniesienie do usługi sieciowej, a także punkty końcowe?
BASEER HAIDER JAFRI

12
Wspomniałeś, żeby to zrobić, jakieś odniesienie do JAK to zrobić?
Zapnologica

Jeśli WSDL nie potrzebuje niestandardowego nagłówka, nie powinieneś go dodawać.
StingyJack

1
Zasadniczo, co jest potrzebne do wysyłania - odbierania SOAP? Czy wystarczy użyć powiązania obsługującego protokół SOAP, takiego jak wsHttpBinding i odwołania do WSDL? Wszystko inne jest takie samo, jak przy użyciu REST (wywoływanie metod WCF, odbieranie odpowiedzi)?
FrenkyB

Zgodziłem się z WSDL, ten pierwszy jest o wiele bardziej złożony i niepotrzebny. Wszystko, czego potrzebujesz, to przejść do referencji usług w projekcie (w starszych wersjach programu Visual Studio), kliknąć prawym przyciskiem myszy, dodać odwołanie do usługi i wprowadzić poprawne szczegóły. Tworzony jest obiekt C #, który należy utworzyć jako zmienną. Cała funkcjonalność usługi WSDL jest następnie ujawniana za pomocą kodu
lllllllllllllIllllIll

19

Myślę, że jest prostszy sposób:

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

To działało jak mistrz. Dodałem parametry do metody CreateSoapEnvelope, aby móc przekazać ciąg XML, adres URL posta i adres URL akcji, aby metody były wielokrotnego użytku i właśnie tego szukałem.
Slippery Pete

najlepsza odpowiedź na moją opinię, ponieważ używa bardziej odpowiedniego HttpClient zamiast przestarzałego WebResponse.
Akmal Salikhov

15

Napisałem bardziej ogólną klasę pomocniczą, która akceptuje słownik oparty na ciągach znaków niestandardowych parametrów, dzięki czemu mogą być ustawiane przez wywołującego bez konieczności ich twardego kodowania. Jest rzeczą oczywistą, że takiej metody należy używać tylko wtedy, gdy chcesz (lub potrzebujesz) ręcznie wydać usługę sieciową opartą na SOAP: w większości scenariuszy zalecanym podejściem byłoby użycie WSDL usługi sieci Web razem z dodatkiem Service Reference Visual Studio funkcja zamiast.

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

Aby uzyskać dodatkowe informacje i szczegóły dotyczące tej klasy, możesz również przeczytać ten post na moim blogu.


1

To jest mój ostateczny kod po 2 dniach wyszukiwania w Google na temat dodawania przestrzeni nazw i wysyłania żądania mydła wraz z kopertą SOAP bez dodawania serwera proxy / odwołania do usługi

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

Wywołaj usługę sieciową SOAP w języku 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);
}

3
Co to jest new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient()?
Chris F Carroll,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.