Arquivo

Textos com Etiquetas ‘SOAP’

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.

21 de junho de 2010

Na semana passada estávamos mexendo em uma aplicação desenvolvida em .NET 2.0. O objetivo era incluir uma nova funcionalidade que dependia de um Web Service SOAP de terceiros.

Para fazer a nova implementação o mais rápido possível, utilizamos o recurso “Add Web Reference…” do Visual Studio 2005 para criar um proxy para o Web Service que queríamos consumir.

Fazendo isso, o Visual Studio 2005 gera algumas classes no arquivo Reference.cs (para visualizá-lo é preciso estar com a opção “Show all files” habilitada na janela Solution Explorer).

A partir dessas classes você pode fazer a comunicação com o Web Service através de simples chamadas de métodos.

CalcPrecoPrazoWS proxy = new CalcPrecoPrazoWS();
Resultado resultado = proxy.Calcular("03478010", "13500313", "0,456");

O problema

Até aqui tudo certo, mas quando testamos a aplicação fazendo a chamada do Web Service, aconteceu o seguinte erro:

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.
at System.Web.Services.Protocols.WebClientProtocol.Ge tWebResponse(WebRequest request)
at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

Depois de pesquisarmos um pouco, descobrimos que as possíveis causas desse problema são:

  • Quando o servidor do Web Service inesperadamente fecha a conexão
  • O time out do servidor do Web Service é muito baixo
  • O servidor do Web Service “reseta” a conexão inesperadamente, algo como uma exceção não tratada

A solução

Quando você chama um método da classe proxy, no exemplo acima a classe CalcPrecoPrazoWS, internamente a classe SoapHttpClientProtocol, que é a classe base do nosso proxy, aciona seu método protegido GetWebRequest, que irá fazer um requisição Web através da classe WebRequest.

Para não mantermos a “conexão viva” na requisição Web, sobrescrevemos o método GetWebRequest da classe SoapHttpClientProtocol, convertendo um objeto WebRequest em um objeto HttpWebRequest e configurando a propriedade KeepAlive para false antes de acionar a requisição.

protected override WebRequest GetWebRequest(Uri uri)
{
    HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
    webRequest.KeepAlive = false;
    webRequest.ProtocolVersion = HttpVersion.Version10;

    return webRequest;
}

Isso pode ser feito no próprio arquivo Reference.cs, dentro da classe proxy que foi gerada pelo Visual Studio 2005. Mas qualquer alteração na referência Web, o Visual Studio 2005 irá gerar novamente o código do arquivo Reference.cs e seu código será apagado.

Então a melhor maneira de fazer isso é utilizar os recursos de classes parciais do .NET e separar seu código em um arquivo separado, como mostrado no exemplo abaixo:

public partial class CalcPrecoPrazoWS
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
        HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
        webRequest.KeepAlive = false;
        webRequest.ProtocolVersion = HttpVersion.Version10;

        return webRequest;
    }
}

Mas não é só isso

Há também um série de outras causas para esse problema, bem como outras possíveis soluções, inclusive quando você está usando WCF no .NET 3.5.

A solução que apresentei funcionou no meu caso. Se ela não resolver seu problema, vale a pena investigar nesse artigo do suporte da Microsoft que lista possíveis causas e soluções:

You receive one or more error messages when you try to make an HTTP request in an application that is built on the .NET Framework 1.1 Service Pack 1
http://support.microsoft.com/kb/915599

Esse artigo é um tanto confuso e mal organizado, mas já é um bom começo.

.NET , , , , , ,