Cliente para enviar solicitud SOAP y recibir respuesta

159

Intentar crear un cliente C # (se desarrollará como un servicio de Windows) que envía solicitudes SOAP a un servicio web (y obtiene los resultados).

De esta pregunta vi este código:

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

Se ve bien, ¿alguien sabe cómo usarlo y si es la mejor práctica?

Base de datos
fuente

Respuestas:

224

Normalmente uso otra forma de hacer lo mismo

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
fuente
1
Es lo mismo, pero he puesto todo aquí, incluida la cadena de solicitud SOAP.
KBBWrite
55
ok, creo que tiene que poner eso en la solicitud SOAP, si tiene una muestra de la carga útil de la solicitud, puede crear una solicitud así. No estoy seguro de qué tipo de seguridad utiliza, si está utilizando WS-Security, el nombre de usuario y la contraseña que puede pasar con su encabezado de solicitud SOAP.
KBBEscribe el
3
Estoy pensando en algo como esto HttpWebRequest webRequest = CreateWebRequest (_url, _action); webRequest.Credentials = nueva NetworkCredential (nombre de usuario, contraseña, dominio);
Base de datos el
3
@hamish: esto es solo un fragmento de código conceptual. No lo considere como un código de calidad de producción.
KBBEscribe el
44
Extremadamente útil y me ayudó a utilizar Telerik Fiddler para enviar POST manualmente a mi servicio web, porque pude ver todos los encabezados que configuró. Muchas gracias.
raddevus
64

Tengo esta solución simple aquí :

Enviando solicitud SOAP y recibiendo respuesta en .NET 4.0 C # sin usar las clases WSDL o 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
fuente
¿Podemos crear un cliente soap xml sin usar string soap xml. Con el uso del código C #. Me gusta como: var request = (HttpWebRequest) WebRequest.Create (uri); request.Method = Common.Method; Por ejemplo, un método de C # que crea más de un cliente xml de soap para los diferentes servicios wsdl con parámetros.
Dvlpr
Recibo el siguiente error y el código termina: 'soap' es un prefijo no declarado. Línea 2, posición 18. ¿Me estoy perdiendo algo? La solicitud de la interfaz de usuario SOAP para mi servicio web se puede encontrar aquí: stackoverflow.com/questions/50430398/…
Vesnog
Funciona con webRequest.Headers.Add("SOAPAction", "http://tempuri.org/.....");Comprobar la acción SOAP que está en SoapUI y usar eso.
Robert Koch
Recibo un error cuando uso los dos puntos en el encabezado SOAPAction. Tengo que hacer: webRequest.Headers.Add (@ "SOAPAction", "SomeAction");
Webs de desarrolladores
¿Cómo se recibe el archivo y se transforma en PDF?
Leandro
20

La mejor práctica es hacer referencia al WSDL y usarlo como una referencia de servicio web. Es más fácil y funciona mejor, pero si no tiene el WSDL, las definiciones XSD son un buen código.

Albernazf
fuente
1
¿Cómo puedo agregar un encabezado personalizado para la solicitud SOAP Si agrego WSDL como referencia de servicio web y también puntos finales?
BASEER HAIDER JAFRI
12
Menciona para hacer esto, ¿alguna referencia sobre CÓMO hacer esto?
Zapnologica
Si el WSDL no quiere un encabezado personalizado, entonces no debería agregar uno.
StingyJack
1
Básicamente, ¿qué se necesita para enviar - recibir SOAP? ¿Es suficiente usar el enlace que admite SOAP como wsHttpBinding y WSDL de referencia? ¿Todo lo demás es lo mismo que usar REST (llamar a métodos WCF, recibir respuesta)?
FrenkyB
Estoy de acuerdo con los WSDL, el primero es mucho más complejo e innecesario. Todo lo que necesita es ir a Referencias de servicio en su proyecto (en versiones anteriores de Visual Studio), hacer clic derecho, agregar referencia de servicio e ingresar los detalles correctos. Se crea un objeto c # que debe crearse como una variable. Toda la funcionalidad del servicio WSDL se expone a través del código
lllllllllllllIllllIll
19

Creo que hay una manera más 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
fuente
Esto funcionó como un campeón. Agregué parámetros al método CreateSoapEnvelope para poder pasar la cadena XML, la URL de publicación y la URL de acción para que los métodos sean reutilizables y era exactamente lo que estaba buscando.
Slippery Pete
La mejor respuesta para mi opinión porque utiliza HttpClient más relevante en lugar de WebResponse obsoleto.
Akmal Salikhov
15

Escribí una clase auxiliar más general que acepta un diccionario basado en cadenas de parámetros personalizados, para que el llamante pueda establecerlos sin tener que codificarlos. No hace falta decir que solo debe usar dicho método cuando desee (o necesite) emitir manualmente un servicio web basado en SOAP: en los escenarios más comunes, el enfoque recomendado sería usar el WSDL del servicio web junto con el Visual Studio de Agregar servicio de referencia característica en su lugar.

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

Para obtener información adicional y detalles sobre esta clase, también puede leer esta publicación en mi blog.

Darkseal
fuente
1

Así que este es mi código final después de buscar en Google durante 2 días cómo agregar un espacio de nombres y hacer una solicitud de jabón junto con el sobre SOAP sin agregar proxy / Referencia de servicio

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
fuente
-5

Llame al servicio 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
fuente
3
¿Qué es new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient()?
Chris F Carroll