Communicationexception: Error in client making HTTP (HTTP.SYS) request to third party Webservice

Asked

Viewed 2,112 times

4

I’m developing for the eSocial for more than a year now, and, I am finding the following error in some customers, when trying to send to the service:

System.ServiceModel.Communicationexception:
Error making HTTP request to https://webservices.producaorestrita.esocial.gov.br/servicos/empregador/enviarloteeventos/WsEnviarLoteEventos.svc. This may be related to the fact that the server certificate is not properly configured with HTTP.SYS in the HTTPS case. This may also have been caused by an incompatibility of the security association between the client and the server.

  ---> System.Net.Webexception: The underlying connection was closed: Unexpected error in an upload.
    ---> System.IO.Ioexception: Unable to read transport connection data: Forced cancellation of an existing connection by remote host.
      ---> System.Net.Sockets.Socketexception: It was forced to cancel an existing connection by the remote host in System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, Socketflags socketFlags)...

On most computers the program is working perfectly, only on some computers this problem happens. My target platform is the . NET Framework 4.7.

I’ve answered two questions myself about this mistake here in the O.R.:

(1) Communication problems with the government-provided web service
(2) https communication error with Webservice

And from the research I’ve done, there are two solutions to the problem:

  1. Set the property ServicePointManager.SecurityProtocol (https://stackoverflow.com/a/33084791/8133067);
  2. Install Windows Update updates (https://stackoverflow.com/a/45494549).

In the case of the first solution: The eSocial service uses the security protocol TLS 1.2, but not always this is the default configuration of the machine. I’ve done this in the code and nay solved in most cases:

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
                                        SecurityProtocolType.Tls11 |
                                        SecurityProtocolType.Tls12;

In the case of the second solution: In the searches I did the problem could happen on outdated Windows 7 computers, and theoretically the update via Windows Update would solve, but in most cases did not solve, and I have already picked up some cases of this error in Windows 10.

I even did a test program, with the message log and the log of trace linked, to see if I could get some more information, but the only other thing I discovered (because of the tracing) is that the error occurs when the message is sent by the channel (communication with Webservice).

Follow the code I’m using to instantiate and call the service:

 const string UrlSvcBase = @"https://webservices.{0}.esocial.gov.br/servicos/empregador/{1}";
 string urlServico = String.Format(UrlSvcBase, "producaorestrita", @"enviarloteeventos/WsEnviarLoteEventos.svc");

 var address = new EndpointAddress(urlServico);
 //var binding = new BasicHttpBinding(BasicHttpsSecurityMode.Transport);
 var binding = new BasicHttpsBinding();  //Disponível desde .NET Framework 4.5
 binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
 // Manual de Orientação do Desenvolvedor v1.4, página 39, item '5.4.5. Validações aplicadas':
 // "O tamanho limite da mensagem SOAP é 750 kbytes."
 // O valor padrão da propriedade MaxReceivedMessageSize é 65.536,
 // que é alterado então para 750 KB * 1024 = 768.000 bytes.
 // Caso contrário, ocorre a exceção:
 //   Exception: System.ServiceModel.CommunicationException
 //   InnerException: System.Exception {System.ServiceModel.QuotaExceededException}
 //   "The maximum message size quota for incoming messages (65536) has been exceeded.
 //    To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element."  
 //   HResult: -2146233087 (0x80131501)
 binding.MaxReceivedMessageSize = 768000;

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
                                        SecurityProtocolType.Tls11 |
                                        SecurityProtocolType.Tls12;

 var wsClient = new WsEnviar.ServicoEnviarLoteEventosClient(binding, address);
 // Variável 'certificado' é do tipo X509Certificate2.
 wsClient.ClientCredentials.ClientCertificate.Certificate = certificado;

 wsClient.Open();
 // Variavel 'lote' é do tipo XElement.
 var retorno = wsClient.EnviarLoteEventos(lote);
 wsClient.Close();

Does anyone have any idea what might cause this mistake, or any idea what else I can do to try to figure out the cause of the problem?

  • Good afternoon Pedro, I am also in this project and we are using the .Tls. I performed a test now and there was no problem sending, already tried it ? Tested environments: Windows 7, Windows Server 2008 R2

  • Hi Felippe, yes, I took a test yesterday using the options Tls | Tls11 | Tls12 and it didn’t work either...

  • I edited the question to include the new options I tried on the property ServicePointManager.SecurityProtocol.

  • how is your Service Revivals ?

  • I don’t quite understand the question Felippe. Do you want to know what is the code that calls the service? I prompt an object of the class ServicoEnviarLoteEventosClient, passing the Binding HTTPS and the URL, inform the digital certificate for connection and then call the method EnviarLoteEventos() of the object, passing the XML batch as argument. I will update the question to include the code as well.

  • There are some differences between our implementations, in the url configuration and certificate part. URL i populate in Servicoenviarloteevents itself, a class you have in the References class.Cs Certificate also in the Servicoenviarloteevents itself

  • Could you tell where you read that the tls version of the eSocial server is 1.2? Because I didn’t find this in the manuals..

  • 1

    Apparently there is a bug in . Net, which does not fallback to previous versions when a version is not supported. Try manually placing version 1.0 and make sure it works. I inspected the package with Fiddler, the system should issue 3 Handshake requests in case of error, one for each version, but this is not happening, the first failed already bursts the exception.

  • @Eprogrammernotfound, the developer’s manual does not actually specify version, it just says that the service uses TLS technology. I came to the conclusion that it was version 1.2 because if you access the URL of the service using IE, right-click on the page and click Properties, the information will appear Connection: TLS 1.2; and also if you run a test on this site here: https://www.ssllabs.com/ssltest/analyze.html?d=webservices.producaorestrita.esocial.gov.br, the result will be that the service is configured for TLS 1.0, 1.1 and 1.2 protocols!

  • @Eprogrammernotfound, but I think you were right! I did a test on the client who was with this problem, reporting only the TLS 1.0 protocol and no more: ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;, and it worked!!! If you write your comment in reply form I will be happy to tag it as a reply and as (very) useful! Thank you very much! I’d been hitting myself with this problem for weeks, and I’d even used Wireshark, but I hadn’t come to any conclusion...

  • I’ve been studying a little more and apparently this fallback control needs a TLS_FALLBACK_SCSV flag, it turns out that this flag introduces a security problem and therefore the servers do not enable it. Intuitively, I believe that’s why . Net doesn’t test other versions. I think it should be done manually like the friend who posted the answer down there.

  • If you want to study more about it and post a detailed response to help the community, follow some interesting materials: rfc7507 and another cryptoexchange issue and rfc5246

Show 7 more comments

1 answer

2


According to the @Eprogrammernotfound comment, it seems to be a.NET bug. The same thing happened to me when transmitting E-finance to Webservice SPED on some Windows 7 and Windows 2008 machines.

I ended up creating a routine that creates a Stack with the protocols I want to use (TLS 1.0, TLS 1.1. and TLS 1.2). Then I will unpacking and assigning one protocol at a time and I will try to send. If it fails, step to the next protocol:

ServicePointManager.SecurityProtocol = (SecurityProtocolType) 0;    

// Pilha com protocolos que vou utilizar
Stack<SecurityProtocolType> protocolosDisponiveis = new Stack<SecurityProtocolType>();
protocolosDisponiveis.Push(SecurityProtocolType.Tls);
protocolosDisponiveis.Push((SecurityProtocolType)768); // TLS 1.1
protocolosDisponiveis.Push((SecurityProtocolType)3072); // TLS 1.2.
var TentarNovamente = false;

do
{
    ServicePointManager.SecurityProtocol = this.protocolosDisponiveis.Pop();

    try
    {
        // Tenta chamar o serviço se der certo ok eu saio fora
        ChamarServico();
        TentarNovamente = false;
    }
    catch (CommunicationException ex)
    {
        TentarNovamente = true;

    }
}
while(TentarNovamente && protocolosDisponiveis.Count() > 0);
  • 1

    Cool Jonas, I even thought about doing something similar, but due to lack of time I finished, at least for now, only using TLS 1.0 always. But I think I’m gonna do something like what you did, thanks! I just don’t understand why you remove all the protocols at the beginning of the code, one by one... wouldn’t it be better to have done ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault (Systemdefault = 0)? Inside the loop, in case of failure I would also do the same thing, since only the current protocol will be present in the property SecurityProtocol.

  • 1

    Also, as a suggestion to leave your code more didactic to those who can stop here in this post, you could add a line like ChamarServico() down the block Try, to make it clear that this is where the service will be called.

  • Good, Pedro! I will follow the hint and test the behavior. The time and legal deadline did not allow you to study the possibilities better. The original idea in removing the protocols assigned by default on the machine was to prevent . NET from trying to establish the connection using any of these. But you’re right. Thank you.

  • 1

    Actually, now thinking, you wouldn’t need to remove even using one line, as I suggested, because in each loop iteration you already play a single protocol on the property ServicePointManager.SecurityProtocol, then that by itself already removes all others! Enjoying, let me ask you, in the version of . NET that you are using Enum SecurityProtocolType had not yet had the values SecurityProtocolType.Tls11 and SecurityProtocolType.Tls12?

  • Good, Pedro. I tested here and it worked following your suggestion. I changed the example code above. About the version of . NET, we used 4.0. And it really doesn’t have the enumerations yet. Thanks for the tips.

Browser other questions tagged

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