Add SOAP Header to SOAP C#

Asked

Viewed 3,159 times

2

I’m trying to add a header customized in one service SOAP using C#. I’ve searched everything and I can’t find a solution that works.

I’m adding the service by Web References of C#. I’ve tried to do override of the method Getwebrequest, but he could not.

The WSDL is this http://app.omie.com.br/api/geral/products/? WSDL

Example as it should be

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://app.omie.com.br/api/v1/geral/clientes/?WSDL">
       <soapenv:Header>
          <app_key>123456789</app_key>
          <app_secret>topSecret</app_secret>
       </soapenv:Header>
   ....

Test code

static void Main(string[] args)
{
    var servico = new omie.Produto.ProdutosCadastro();            
    servico.autenticacao = new omie.Produto.Autenticacao();
    servico.autenticacao.app_key = "123456";
    servico.autenticacao.app_secret = "123456789";

    var dados = new omie.Produto.produto_servico_list_request();
    dados.pagina = "1";
    dados.registros_por_pagina = "50";
    dados.apenas_importado_api = "N";
    dados.filtrar_apenas_omiepdv = "N";

    var produtos = servico.ListarProdutosResumido(dados);

    Console.WriteLine(produtos.total_de_registros.ToString());
}

The test code was a suggestion of this post

https://bytes.com/topic/net/answers/560786-how-add-soap-header-soap-message Search by text:

That was already described in my Previous post

In addition, the SOAP class was extended with these elements:

namespace omieTestes.omie.Produto
{
    public partial class ProdutosCadastro : System.Web.Services.Protocols.SoapHttpClientProtocol
    {
        public Autenticacao autenticacao;
    }

    //[XmlRoot(Namespace = "http://app.omie.com.br/autenticacao")]    
    public class Autenticacao : SoapHeader
    {
        public string app_key;
        public string app_secret;
    }
}

What I found bad is that if you update the reference, you lose the implementation:

[System.Web.Services.Protocols.SoapRpcMethodAttribute("http://app.omie.com.br/api/v1/geral/produtos/?WSDLListarProdutosResumido", RequestNamespace="http://app.omie.com.br/api/v1/geral/produtos/?WSDL", ResponseNamespace="http://app.omie.com.br/api/v1/geral/produtos/?WSDL")]
    [SoapHeader("autenticacao", Direction = SoapHeaderDirection.In)]
    [return: System.Xml.Serialization.SoapElementAttribute("produto_servico_list_response")]        
    public produto_servico_list_response ListarProdutosResumido(produto_servico_list_request produto_servico_list_request) {
        object[] results = this.Invoke("ListarProdutosResumido", new object[] {
                    produto_servico_list_request});
        return ((produto_servico_list_response)(results[0]));
    }

Line placed in the hand

[SoapHeader("autenticacao", Direction = SoapHeaderDirection.In)]
  • You can use Operationcontext for this. Show your client code to help show you how to do.

  • And your client configuration file, the part where declares the <endpoint>

  • @Ricardopunctual edited the post... see if improved.

  • Yes, it helped, I wrote a reply with two solutions, I hope it helps

  • Marlontiedt you are using web Reference and the answer given by @Ricardopunctual uses Servicereference (which uses the WCF classes). Webreference is deprecated and is not advised to use it for new developments. To do this with Webreference you would probably have to use WSE 3.0 and implement a Soapfilter. However the WSE plugin is no longer supported in Visual Studio 2015 (in previous versions you can turn around but not in 2015).

  • @nflash is true, there are some things you can’t do using a proxy created by Webreference that is obsolete.

  • @nflash but Webreference is not for SOAP (webservice) and Servicereference is for WCF services? Is there any way to not have endpoint Binding when using Servicereference? Because my application is a service, and has a friendly screen and if using Servicereference I have to put the URL in both app.config.

  • @Marlontiedt WCF is a framework that allows, among other things, the creation and access to Webservices. Supports Soap (1.1 and 1.2), REST, TCP, Messagequeue, among others. The good thing about WCF is that it abstracts the protocol used (allowing even having the same service exposed in multiple protocols using multiple endpoints) through the same API. In this case you would only be using the proxy (client) generated by Servicereference (this proxy extends to class Clientbase<T>). You should have no problem using this proxy to access a Webservice Soap. And it’s worth learning WCF.

Show 3 more comments

3 answers

2

This implementation seems a little complicated. I have several services here that use values in Header, I’ll show you two solutions that can suit you:

Assign values in Header directly in the Endpoint configuration file:
This is nice because services that have configuration files, do not need to have the Header settings in the code, unless your service creates Servicehost in the code. Host services on IIS can send information on Header just by adding it to Endpoint.

<client>
  <endpoint address="http://dominio/NomeServico.svc"
      binding="basicHttpBinding" contract="Contrato" name="NomeConfiguracao">
    <headers>
        <app_key>123456789</app_key>
        <app_secret>topSecret</app_secret>
    </headers>
  </endpoint>
</client>

This is the simplest way to do.

Manipulating Endpoint in code:
You can manipulate the Endpoint after creating your client and before calling an operation. This is interesting because you can pass variable values and also that are not exposed in the configuration file, but have to compile the code:

ServicoWcf cliente = new ServicoWcf();
var endpointPersonalizado = new EndpointAddressBuilder(cliente.Endpoint.Address);
endpointPersonalizado.Headers.Add( AddressHeader.CreateAddressHeader("app_key", string.Empty, "123456789")); 
endpointPersonalizado.Headers.Add( AddressHeader.CreateAddressHeader("app_secret", string.Empty, "topSecret")); 
cliente.Endpoint.Address = endpointPersonalizado.ToEndpointAddress();

You can also manipulate the OperationContextScope in the client and add the Header, but I prefer the above implementations. I hope it helps.

  • Ricardo, how to do when inside Header has an 'Authenticate' object and inside it we have the login and password entries? How to add this object inside Header? By code and not manually.

  • this is very strange, because the header is a dictionary of type <string, string>, that is, a key and a value as it is in the above example, no objects are placed inside the header, I honestly don’t know how to do this, and I believe it’s not possible because of the nature of header

  • This is the header expected by WS <soapenv:Header> <authenticate> <cnpj>xxxxxx</cnpj> <key>xxxxxx</key> </authenticate> </soapenv:Header>.

  • 1

    ah, adding a Soap header is something else. There’s some way to do it, but you’re using it. NET, you can add the header to your contract with the attribute [MessageHeader]

  • 1

    to take a north, suppose your contract is the class "Contract", the class you want to add in the Soap header is "Authenticate". You can use it like this: [DataContract]public class Contrato { [MessageHeader]public Contrato contrato {get; set; } ..

  • 1

    That’s right. I even asked a question here on the website about it and a colleague helped me. I also thank you for the explanation and help.

Show 1 more comment

2

Try to do it this way:

  ProdutoCadastroService.ProdutosCadastroSoapClient produtoCadastroWS = new    ProdutoCadastroService.ProdutosCadastroSoapClient();
  autenticaWsHeader(produtoCadastroWS);

  private static void autenticaWsHeader(ProdutosCadastroSoapClient produtoCadastroWS)
  {
        new OperationContextScope(produtoCadastroWS.InnerChannel);

        HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
        requestMessage.Headers["Username"] = "admin";
        requestMessage.Headers["Password"] = "123";
        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
  }

-2

using (Endpoint1ws.Meuobjectclient proxy = new Endpoint1ws.Meuobjectclient("Basichttpbinding_imeuobject1") { using (new System.ServiceModel.Operationcontextscope(proxy.Innerchannel)) { Messageheader head = Messageheader.Createheader("app_hey", "https://meuenderecoNamespace/", "123456"); AND Operationcontext.Current.Outgoingmessageheaders.Add(head); var invoice = proxy.Get something();

            }
        }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.