HttpWebRequest Configuracao - Belo Horizonte/MG

Bom dia!
Primeiramente parabéns aos criadores da comunidade pela maravilhosa idéia!

Colegas, estou necessitando comunicar via SOAP com o servidor bhissdigital e estou trabalhando com o HttpWebRequest (c#).
Alguém conhece um exemplo de configuração/comunicação em c#?

Muito obrigado!
Ivan.

Olá!

Precisa importar o Web Service no C#.

Antes de tudo, acesse a URL https://bhissdigital.pbh.gov.br/bhiss-ws/nfse?wsdl e salve como um arquivo .wsdl .

Depois abra a opção de importar o webservice:
image

Clique em Advanced…
image

Agora em Add Web Reference
image

Informe o local onde salvou o arquivo e clique no botão do lado para acessar:
image

De um nome para o webservice e clique em Add Reference

Para funcionar com a PBH, você vai precisar de uma classe auxiliar para informar o certificado durante a requisição:

    //Classes Auxiliares para adicionar o Certificado a Requisição
    public class WS_3106200A_Custom : WS_3106200A.NfseWSService
    {
        private HttpStatusCode cLastCode;
        private X509Certificate2 cCertificado;

        public X509Certificate2 Certificado
        {
            get { return cCertificado; }
            set { cCertificado = value; }
        }

        public HttpStatusCode lastCode { get { return cLastCode; } }

        public WS_3106200A_Custom(
            X509Certificate2 pCertificado,
            string pUrl)
        {
            Certificado = pCertificado;
            Url = pUrl;
        }

        // Override para informar o certificado
        protected override System.Net.WebRequest GetWebRequest(Uri uri)
        {
            // instanciar o objeto de requisição para a Url informada no construtor da classe
            System.Net.WebRequest wr = System.Net.WebRequest.Create(new Uri(Url));
            System.Net.HttpWebRequest hr = ((System.Net.HttpWebRequest)wr);

            // incluir o certificado digital na requisição
            hr.ClientCertificates.Clear();
            if (cCertificado != null)
                hr.ClientCertificates.Add(cCertificado);
            hr.PreAuthenticate = true;
            hr.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);

            //Corrige: "A solicitação foi anulada: Não foi possível criar um canal seguro para SSL/TLS."
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            ServicePointManager.Expect100Continue = true;

            return wr;
        }

        // Guardar o ultimo StatusCode
        protected override System.Net.WebResponse GetWebResponse(System.Net.WebRequest request)
        {
            System.Net.WebResponse wr = base.GetWebResponse(request);
            System.Net.HttpWebResponse hr = ((System.Net.HttpWebResponse)wr);
            cLastCode = hr.StatusCode;

            return wr;
        }

        // Callback usado para validar o certificate com a SSL conversation
        private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
        {
            return true;
        }

    }

Eu uso uma classe de retorno na minha consulta:

    public class RetornoXML
    {
        private List<ErroXML> errorList = new List<ErroXML>();

        public bool Sucesso { set; get; }
        public List<ErroXML> Erros
        {
            get { return errorList; }
            set { errorList = value; }
        }

        public class ErroXML
        {
            public string Codigo { set; get; }
            public string Descricao { set; get; }
            public string Correcao { set; get; }
        }

        public string url { set; get; }
        public string protocolo { set; get; }
        public string numeroNota { set; get; }
        public string codigoVerificacao { set; get; }
        public DateTime dataEmissao { set; get; }
        public DateTime dataCancelamento { set; get; }
    }

Assim o resto fica fácil:

            WS_3106200A_Custom ws1 = new WS_3106200A_Custom(certificado, "https://bhissdigital.pbh.gov.br/bhiss-ws/nfse");
            RetornoXML retorno = new RetornoXML();

            string b = "";
            string s = "";
            try
            {
                //Cabeçalho
                b = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                    "<cabecalho xmlns = \"http://www.abrasf.org.br/nfse.xsd\" versao = \"1.00\" >\n" +
                    "<versaoDados>1.00</versaoDados>\n" +
                    "</cabecalho>";

                //Envia Lote
                s = "<-- XML ASSINADO --> ";
                s = ws1.GerarNfse(b, s);
                s = s.Replace("&gt;" , ">").Replace("&lt;", "<");

                try
                {
                    XDocument doc = new XDocument();

                    //Safe UTF preamble
                    using (var xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(s)))
                    using (var xmlReader = new XmlTextReader(xmlStream))
                    {
                        doc = XDocument.Load(xmlReader);
                        doc.Save(System.IO.Path.Combine(path, filename.Replace(".xml", ".ret.xml"))); //salvar arquivo retorno
                    }

                    //Possui Erro?
                    var e = from AnyElement in doc.Descendants() where (AnyElement.Name.LocalName == "MensagemRetorno") select AnyElement; //Ignora Namescape
                    foreach (XElement c in e)
                    {
                        retorno.Sucesso = false;
                        RetornoXML.ErroXML z = new RetornoXML.ErroXML();
                        z.Codigo = c.Element(XName.Get("Codigo", "http://www.abrasf.org.br/nfse.xsd")).Value;
                        z.Descricao = c.Element(XName.Get("Mensagem", "http://www.abrasf.org.br/nfse.xsd")).Value;
                        //z.Correcao = c.Element(XName.Get("Correcao", "http://www.abrasf.org.br/nfse.xsd")).Value;
                        retorno.Erros.Add(z);
                    }

                    //Salvar nota
                    e = from AnyElement in doc.Descendants() where (AnyElement.Name.LocalName == "InfNfse") select AnyElement;
                    foreach (XElement i in e)
                    {
                        retorno.Sucesso = true;
                        try
                        {
                            retorno.numeroNota = i.Element(XName.Get("Numero", "http://www.abrasf.org.br/nfse.xsd")).Value;
                            retorno.codigoVerificacao = i.Element(XName.Get("CodigoVerificacao", "http://www.abrasf.org.br/nfse.xsd")).Value;
                            string data = i.Element(XName.Get("DataEmissao", "http://www.abrasf.org.br/nfse.xsd")).Value;
                            retorno.dataEmissao = DateTime.ParseExact(data, "yyyy-MM-ddTHH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);

                            retorno.url = "https://bhissdigital.pbh.gov.br/nfse/pages/consultaNFS-e_cidadao.jsf";
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }

                }
                catch (Exception ex)
                {
                    retorno.Sucesso = false;
                    RetornoXML.ErroXML z = new RetornoXML.ErroXML();
                    z.Codigo = "501";
                    z.Descricao = ex.Message;
                    retorno.Erros.Add(z);
                }

            }
            catch (System.Web.Services.Protocols.SoapException error)
            {

                retorno.Sucesso = false;
                RetornoXML.ErroXML z = new RetornoXML.ErroXML();
                z.Codigo = ws1.lastCode.ToString();
                z.Descricao = error.Message;
                retorno.Erros.Add(z);
            }

            return retorno;
        }

Mestre Luizvaz muito obrigado pela ajuda! Já irei fazer os testes aqui! Mestre espero poder retribuir vossa generosidade!

Boa tarde à todos! Em especial ao professor @luizvaz!

Professor @luizvaz, novamente obrigado por suas informações! Graças à elas consegui êxito!

Infelizmente como estou utilizando net core, os métodos gerados para o “wsdl” são diferentes. Mas consegui via comunicação SOAP. Para colaborar com todos os colegas, posto o código que já está operante.

Novamente agradeço ao professor e à todos os demais!

using System;
using System.Collections.Generic;
using System.Text;


using System.Data;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Xml;



namespace Dgt100.Tools
{
    public class CaWebOpenNfse
    {

        public X509Certificate2 gcer;
        public DataSet gds;
        public string gfil = "";                    //http ret file write
        public string gret = "";                    //http ret
        public string gsoap = "";                   //soap msg
        public string gsoapAction = "";             //soap action 
        public string gurl = "";                    //http url 
        public string gurl2 = "";

        public HttpWebRequest ghttpWR;              //http cli


        //-------------------------------------------------
        //
        //WEBSERVICE COMUNICACAO
        //
        //-------------------------------------------------
        public string QxHttpNfs(XmlNode xml)
        {
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

                gret = string.Empty;
                gsoap = xml.OuterXml;

                QxCfg(gurl);                                                            //ghttpWR configura, visualizacao mais clara

                Stream reqStream = ghttpWR.GetRequestStream();
                StreamWriter streamWriter = new StreamWriter(reqStream);
                streamWriter.Write(gsoap, 0, Encoding.ASCII.GetBytes(gsoap).Length);
                streamWriter.Close();

                WebResponse webResponse = ghttpWR.GetResponse();
                Stream respStream = webResponse.GetResponseStream();
                StreamReader streamReader = new StreamReader(respStream);

                gret = streamReader.ReadToEnd();
                gret.QpXml().QpArqTxt(gfil);
                return gret;
            }
            catch (WebException ex)
            {
                string s1 = gurl;
                string s3 = "";
                string x1 = new FcXml().Qprint(gsoap);
                if (ex.InnerException != null) s3 = ex.InnerException.Message;          

                if (ex.Response == null) new FcDic().Qthrow("web.200", s3);
                using (var stream = ex.Response.GetResponseStream())
                using (var reader = new StreamReader(stream))
                {
                    string s2 = reader.ReadToEnd();
                    new FcDic().Qthrow("web.200", s2);                                  //força throw padrao
                }
                throw;
            }
        }
        public void QxCfg(string url1)
        {
            ghttpWR = (HttpWebRequest)WebRequest.Create(url1);                          
                                                                                        
            ghttpWR.PreAuthenticate = true;
            ghttpWR.ServicePoint.Expect100Continue = false;                             
            ghttpWR.CookieContainer = new CookieContainer();
            ghttpWR.Timeout = 30000;

            ghttpWR.Headers.Add("SOAPAction: " + gsoapAction);
            ghttpWR.ContentType = "application/soap+xml;charset=utf-8";
            ghttpWR.ContentType = "text/xml;charset=UTF-8";                             //NESTE PONTO ATENCAO!!!!!
            ghttpWR.Method = WebRequestMethods.Http.Post;
            ghttpWR.Accept = "text/xml";

            ghttpWR.KeepAlive = true;
            ghttpWR.ClientCertificates.Add(gcer);
            ghttpWR.UseDefaultCredentials = true;                                       

            ghttpWR.ContentLength = Encoding.ASCII.GetBytes(gsoap).Length;
            ghttpWR.Proxy = WebRequest.GetSystemWebProxy();
            ghttpWR.SendChunked = false;                                                 
        }


    }
}
1 curtida

As chamadas SOAP na verdade são faceis de reproduzir.
Não passam de um XML para envio e recebimento.

O que o .NET e outras frameworks ou ferramentas fazem é tentar automatizar os procedimentos para o desenvolvedor.
Mas como é uma especificação muito aberta, as ferramentas acabam não conseguindo entender muito bem o que está acontecendo durante a comunicação.

Isso porque quem desenvolveu o não sabe muito bem o que está fazendo.

Por isso para cada prefeitura e cada empresa desenvolvedora da solução vai ter um padrão diferente.
Mesmo jurando de pé junto que é compatível com o padrão ABRASF.

O que sempre faço é analizar a comunicação HTTP.
Assim eu sei exatamente o que está sendo enviado e recebido.

Parabens por ter conseguido implementar.

Este tópico foi fechado automaticamente 30 dias depois da última resposta. Novas respostas não são mais permitidas.