Client pour envoyer une requête SOAP et recevoir une réponse

159

Tentative de création d'un client C # (qui sera développé en tant que service Windows) qui envoie des requêtes SOAP à un service Web (et obtient les résultats).

De cette question, j'ai vu ce 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; }
}

Ça a l'air bien, n'importe qui sait comment l'utiliser et si c'est la meilleure pratique?

Base de données
la source

Réponses:

224

J'utilise normalement une autre façon de faire de même

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);
    }
}
KBBWrite
la source
1
C'est samething, mais j'ai tout mis ici, y compris la chaîne de requête SOAP.
KBBÉcrire le
5
ok, je pense que vous devez mettre cela dans la requête SOAP, si vous avez un échantillon de la charge utile de la requête, vous pouvez créer une requête comme ça. Vous ne savez pas quel type de sécurité vous utilisez, si vous utilisez WS-Security, le nom d'utilisateur et le mot de passe que vous pouvez transmettre avec l'en-tête de votre demande SOAP.
KBBÉcrire le
3
Je pense à quelque chose comme ceci HttpWebRequest webRequest = CreateWebRequest (_url, _action); webRequest.Credentials = new NetworkCredential (nom d'utilisateur, mot de passe, domaine);
Base de données du
3
@hamish: ce n'est qu'un extrait de code conceptuel. Ne le considérez pas comme un code de qualité de production.
KBBÉcrit le
4
Extrêmement utile et m'a aidé à utiliser Telerik Fiddler pour effectuer manuellement un POST sur mon service Web, car je pouvais voir tous les en-têtes que vous avez définis. Merci beaucoup.
raddevus
64

J'ai cette solution simple ici :

Envoi d'une requête SOAP et réception d'une réponse dans .NET 4.0 C # sans utiliser le WSDL ou les classes 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();
        }
    }
Yuliia Ashomok
la source
Pouvons-nous créer un client soap xml sans utiliser la chaîne soap xml. Avec l'utilisation du code c #. Comme: var request = (HttpWebRequest) WebRequest.Create (uri); request.Method = Common.Method; Par exemple, une méthode c # qui crée plusieurs clients soap xml vers les différents services wsdl avec des paramètres.
Dvlpr
J'obtiens l'erreur suivante et le code se termine: «soap» est un préfixe non déclaré. Ligne 2, position 18. Est -ce que je manque quelque chose? La demande de l'interface utilisateur SOAP pour mon service Web peut être trouvée ici: stackoverflow.com/questions/50430398/…
Vesnog
Fonctionne avec webRequest.Headers.Add("SOAPAction", "http://tempuri.org/.....");Vérifiez l'action SOAP qui se trouve dans SoapUI et utilisez-la.
Robert Koch
J'obtiens une erreur lorsque j'utilise les deux points dans l'en-tête SOAPAction. Je dois faire: webRequest.Headers.Add (@ "SOAPAction", "SomeAction");
Developer Webs
comment reçu le fichier et transformer en PDF?
Leandro
20

La meilleure pratique consiste à référencer le WSDL et à l'utiliser comme une référence de service Web. C'est plus facile et fonctionne mieux, mais si vous n'avez pas le WSDL, les définitions XSD sont un bon morceau de code.

Albernazf
la source
1
Comment puis-je ajouter un en-tête personnalisé pour la demande SOAP Si j'ajoute WSDL en tant que référence de service Web et également des points de terminaison ???
BASEER HAIDER JAFRI
12
Vous mentionnez pour faire cela, une référence sur COMMENT faire cela?
Zapnologica
Si le WSDL ne veut pas d'en-tête personnalisé, vous ne devriez pas en ajouter un.
StingyJack
1
Fondamentalement, que faut-il pour envoyer - recevoir SOAP? Est-il suffisant d'utiliser une liaison qui prend en charge SOAP comme wsHttpBinding et référence WSDL? Tout le reste est identique à l'utilisation de REST (appel des méthodes WCF, réception d'une réponse)?
FrenkyB
Je suis d'accord avec le WSDL, le premier est bien plus complexe et inutile. Tout ce dont vous avez besoin est d'accéder aux références de service dans votre projet (dans les anciennes versions de Visual Studio), cliquez avec le bouton droit, ajoutez une référence de service et entrez les détails corrects. Un objet c # est créé qui doit être créé en tant que variable. Toutes les fonctionnalités du service WSDL sont ensuite exposées via le code
lllllllllllllIllllIll
19

Je pense qu'il existe un moyen plus simple:

 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);
       }
 }
debiasej
la source
Cela a fonctionné comme un champion. J'ai ajouté des paramètres à la méthode CreateSoapEnvelope pour pouvoir passer la chaîne XML, l'URL de publication et l'URL d'action pour rendre les méthodes réutilisables et c'était exactement ce que je recherchais.
Slippery Pete
meilleure réponse à mon avis car il utilise HttpClient plus pertinent au lieu de WebResponse obsolète.
Akmal Salikhov le
15

J'ai écrit une classe d'assistance plus générale qui accepte un dictionnaire basé sur des chaînes de paramètres personnalisés, afin qu'ils puissent être définis par l'appelant sans avoir à les coder en dur. Il va sans dire que vous ne devez utiliser cette méthode que lorsque vous souhaitez (ou avez besoin) d'émettre manuellement un service Web basé sur SOAP: dans la plupart des scénarios courants, l'approche recommandée consisterait à utiliser le Web Service WSDL avec l' ajout de référence de service Visual Studio fonctionnalité à la place.

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

Pour plus d'informations et de détails concernant cette classe, vous pouvez également lire cet article sur mon blog.

Darkseal
la source
1

Voici donc mon code final après avoir cherché sur Google pendant 2 jours sur la façon d'ajouter un espace de noms et de faire une demande de savon avec l'enveloppe SOAP sans ajouter de proxy / référence de service

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;
    }
}
Faisal Ansari
la source
-5

Appeler le service Web SOAP en 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);
}
vipul kumar
la source
3
C'est quoi new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient()?
Chris F Carroll