Cliente para enviar solicitação SOAP e receber resposta

159

Tentando criar um cliente C # (será desenvolvido como um serviço do Windows) que envia solicitações SOAP para um serviço da Web (e obtém os resultados).

A partir desta pergunta , 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; }
}

Parece bom, alguém sabe como usá-lo e se é a melhor prática?

Base de dados
fonte

Respostas:

224

Eu normalmente uso outra maneira de fazer o mesmo

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
fonte
1
É algo, mas eu coloquei tudo aqui, incluindo a string de solicitação SOAP.
precisa saber é o seguinte
5
ok, acho que você deve colocar isso na solicitação SOAP, se você tiver uma amostra da carga útil da solicitação, poderá criar uma solicitação assim. Não tenho certeza de que tipo de segurança você usa. Se você estiver usando o WS-Security, o nome de usuário e a senha podem ser passados ​​com o cabeçalho da solicitação SOAP.
precisa saber é o seguinte
3
Estou pensando em algo assim HttpWebRequest webRequest = CreateWebRequest (_url, _action); webRequest.Credentials = new NetworkCredential (nome de usuário, senha, domínio);
Base de dados
3
@hamish: este é apenas um trecho de código conceitual. Não considere isso como um código de qualidade de produção.
KBBWrite
4
Extremamente útil e me ajudou a trabalhar com o Telerik Fiddler para o POST manual no meu serviço da Web, porque eu podia ver todos os cabeçalhos que você definiu. Muito obrigado.
Raddevus
64

Eu tenho essa solução simples aqui :

Enviando solicitação SOAP e recebendo resposta no .NET 4.0 C # sem usar as classes WSDL ou 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
fonte
Podemos criar cliente xml de sabão sem usar xml de sabão de string. Com o uso de código c #. Como: var request = (HttpWebRequest) WebRequest.Create (uri); request.Method = Common.Method; Por exemplo, um método c # que cria mais de um cliente soap xml para os diferentes serviços wsdl com parâmetros.
Dvlpr 20/05
Estou recebendo o seguinte erro e o código termina: 'soap' é um prefixo não declarado. Linha 2, posição 18. Estou faltando alguma coisa? A solicitação da interface do usuário SOAP para o meu serviço da web pode ser encontrada aqui: stackoverflow.com/questions/50430398/…
Vesnog
Funciona com webRequest.Headers.Add("SOAPAction", "http://tempuri.org/.....");Verifique a ação SOAP que está no SoapUI e use isso.
Robert Koch
Eu recebo um erro quando uso os dois pontos no cabeçalho SOAPAction. Eu tenho que fazer: webRequest.Headers.Add (@ "SOAPAction", "SomeAction");
Webs de desenvolvedores
como arquivo recebido e transformar em PDF?
Leandro
20

A melhor prática é fazer referência ao WSDL e usá-lo como uma referência de serviço da web. É mais fácil e funciona melhor, mas se você não possui o WSDL, as definições de XSD são um bom código.

Albernazf
fonte
1
Como posso adicionar um cabeçalho personalizado para solicitação SOAP? Se eu adicionar o WSDL como uma referência de serviço da web e também pontos finais ???
BASEER HAIDER JAFRI
12
Você menciona para fazer isso, alguma referência sobre como fazer isso?
Zapnologica
Se o WSDL não deseja um cabeçalho personalizado, você não deve adicionar um.
StingyJack #
1
Basicamente, o que é necessário para enviar - receber SOAP? É suficiente usar a ligação que suporta SOAP, como wsHttpBinding e referência WSDL? Tudo o resto é o mesmo que usar REST (chamando métodos WCF, recebendo resposta)?
precisa saber é o seguinte
Concordei com o WSDL, o primeiro é muito mais complexo e desnecessário. Tudo o que você precisa é acessar as Referências de serviço no seu projeto (nas versões anteriores do Visual Studio), clique com o botão direito do mouse, adicione a referência de serviço e insira os detalhes corretos. É criado um objeto c # que deve ser criado como uma variável. Todas as funcionalidades do serviço WSDL são então expostas por meio do código
lllllllllllllIllllIll
19

Eu acho que existe uma maneira mais simples:

 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
fonte
Isso funcionou como um campeão. Adicionei parâmetros ao método CreateSoapEnvelope para poder transmitir a string XML, URL de postagem e URL de ação para tornar os métodos reutilizáveis ​​e era exatamente o que eu estava procurando.
Slippery Pete
melhor resposta para minha opinião, porque usa HttpClient mais relevante em vez de WebResponse obsoleto.
Akmal Salikhov 14/01
15

Eu escrevi uma classe auxiliar mais geral que aceita um dicionário baseado em string de parâmetros personalizados, para que eles possam ser definidos pelo chamador sem precisar codificá-los. Escusado será dizer que você só deve usar esse método quando desejar (ou precisar) emitir manualmente um serviço da Web baseado em SOAP: nos cenários mais comuns, a abordagem recomendada seria usar o WSDL de Serviço da Web junto com o Add Studio Reference Visual Service Reference recurso em vez disso.

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 informações e detalhes adicionais sobre esta aula, você também pode ler esta postagem no meu blog.

Darkseal
fonte
1

Portanto, este é o meu código final, depois de pesquisar no Google por 2 dias, sobre como adicionar um namespace e fazer uma solicitação de sabão junto com o envelope SOAP sem adicionar proxy / referência de serviço

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

Ligue para o serviço web SOAP em 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
fonte
3
O que é new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient()?
Chris F Carroll