Search code examples
c#asp.net-coreiishttpwebrequest

C# & ASP.NET Core Web API runs in my local IIS, but not in the staging server IIS. HttpWebResponse execption on POST request


I need some help to find the problem, I'm really lost here. I'm already a developer, but I'm working with C# about three months now.

Let me start with the environment:

Local:

  • Windows 10 Pro 22H2 (Compilation 19045.3930)
  • Visual Studio 2022 (Version 17.8.5)
  • IIS (Version 10.0.19041.3691)
  • Insomnia (Version 8.6.0) to test the API.

Staging Server

  • Windows Server 2016 Standard 1607 (Compilation 14393.4770)
  • IIS (Version 10.0.14393.0)
  • .NET 6.0.2 (Version 6.0.2.22064)
  • .NET Core 2.0.7 (Version 2.0.40409.231)
  • .NET Core 2.1.4 (Version 2.1.13214.0)
  • .NET Core 2.2.2 (Version 2.2.2.0)
  • .NET Core 3.1.9 (Version 3.1.9.20473)

I have two solutions: a DLL (.NET Standard 2.0) and my API (.NET 6.0).

I guess I have a simple problem... When I run may API from Visual Studio or when I publish and run in my local IIS, works fine. But, when I copy the publish files to the staging server, doesn't work.

In the staging server there is another projects from others teams that work fine, all that projects are in .NET Framework, mine is the only one in .NET Core.

That's the output from InnerException.StackTrace:

Error[[[An error occurred while sending the request.]]] at System.Net.HttpWebRequest.GetResponse()\r\n at Uni.Business.DFe.ConsumirBase.ExecutarServico(XmlDocument xml, Object servico, X509Certificate2 certificado)\r\n at Uni.Business.DFe.Servicos.ServicoBase.Executar()\r\n at Uni.Business.DFe.Servicos.NFCom.ServicoBase.Executar()\r\n at NFeModelo62.Handlers.RecepcaoHandler.HandleStatusServico62() in C:\repositorios\git\NFeModelo62\NFeModelo62Api\NFeModelo62Api\NFeModelo62\Handlers\RecepcaoHandler.cs:line 366 [[[An error occurred while sending the request.]]] at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageHandlerStage.Send(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageHandlerStage.Send(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.SocketsHttpHandler.Send(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.Send(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpClient.Send(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)\r\n at System.Net.HttpWebRequest.SendRequest(Boolean async)\r\n at System.Net.HttpWebRequest.GetResponse()

This is the method that generates the exception

/// <summary>
/// Estabelece conexão com o Webservice e faz o envio do XML e recupera o retorno. Conteúdo retornado pelo webservice pode ser recuperado através das propriedades RetornoServicoXML ou RetornoServicoString.
/// </summary>
/// <param name="xml">XML a ser enviado para o webservice</param>
/// <param name="servico">Parâmetros para execução do serviço (parâmetros do soap)</param>
/// <param name="certificado">Certificado digital a ser utilizado na conexão com os serviços</param>
public void ExecutarServico(XmlDocument xml, object servico, X509Certificate2 certificado)
{
    var soap = (WSSoap)servico;

    if (certificado == null && soap.UsaCertificadoDigital)
    {
        throw new CertificadoDigitalException();
    }

    TratarScapeEnvio = false;
    TratarScapeRetorno = false;

    if (soap.SoapString.IndexOf("{xmlBodyScape}") > 0)
    {
        TratarScapeEnvio = true;
        TratarScapeRetorno = true;
    }
    else if (soap.SoapString.IndexOf("{xmlBodyScapeEnvio}") > 0)
    {
        TratarScapeEnvio = true;
        TratarScapeRetorno = false;
    }
    else if (soap.SoapString.IndexOf("{xmlBodyScapeRetorno}") > 0)
    {
        TratarScapeEnvio = false;
        TratarScapeRetorno = true;
    }

    var urlpost = new Uri(soap.EnderecoWeb);
    var soapXML = EnveloparXML(soap, xml.OuterXml);
    var buffer2 = Encoding.UTF8.GetBytes(soapXML);

    ServicePointManager.Expect100Continue = false;
    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(RetornoValidacao);
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

    var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(urlpost);
    httpWebRequest.Headers.Add("SOAPAction: " + soap.ActionWeb);
    httpWebRequest.CookieContainer = cookies;
    httpWebRequest.Timeout = soap.TimeOutWebServiceConnect;
    httpWebRequest.ContentType = (string.IsNullOrEmpty(soap.ContentType) ? "application/soap+xml; charset=utf-8;" : soap.ContentType);
    httpWebRequest.Method = "POST";

    if (soap.UsaCertificadoDigital)
    {
        httpWebRequest.ClientCertificates.Add(certificado);
    }

    httpWebRequest.ContentLength = buffer2.Length;

    //Definir dados para conexão com proxy
    if (soap.Proxy != null)
    {
        httpWebRequest.Proxy = soap.Proxy;
    }

    var postData = httpWebRequest.GetRequestStream();
    postData.Write(buffer2, 0, buffer2.Length);
    postData.Close();

    WebException webException = null;
    WebResponse responsePost = null;

    try
    {
        responsePost = (HttpWebResponse)httpWebRequest.GetResponse();
    }
    catch (Exception e)
    {
        throw;
    }
    //catch (WebException ex)
    //{
    //    webException = ex;
    //    responsePost = ex.Response;

    //    if (ex.Response == null)
    //    {
    //        throw (ex);
    //    }
    //}

    var streamPost = responsePost.GetResponseStream();

    var encoding = Encoding.GetEncoding(soap.EncodingRetorno);

    var streamReaderResponse = new StreamReader(streamPost, encoding);
    var conteudoRetorno = streamReaderResponse.ReadToEnd();

    var retornoXml = new XmlDocument();

    try
    {
        retornoXml.LoadXml(conteudoRetorno);
    }
    catch (XmlException ex)
    {
        if (webException != null)
        {
            throw (webException);
        }

        throw (ex);
    }
    catch (Exception ex)
    {
        throw (ex);
    }

    if (soap.TagRetorno.ToLower() != "prop:innertext")
    {
        var tagRetorno = soap.TagRetorno;

        if (soap.TipoAmbiente == TipoAmbiente.Homologacao && !string.IsNullOrWhiteSpace(soap.TagRetornoHomologacao))
        {
            tagRetorno = soap.TagRetornoHomologacao;
        }

        if (retornoXml.GetElementsByTagName(tagRetorno)[0] == null)
        {
            throw new Exception("Não foi possível localizar a tag <" + tagRetorno + "> no XML retornado pelo webservice.\r\n\r\n" +
                    "Conteúdo retornado pelo servidor:\r\n\r\n" +
                retornoXml.InnerXml);
        }

        if (TratarScapeRetorno)
        {
            RetornoServicoString = retornoXml.GetElementsByTagName(tagRetorno)[0].ChildNodes[0].InnerText;
        }
        else
        {
            RetornoServicoString = retornoXml.GetElementsByTagName(tagRetorno)[0].ChildNodes[0].OuterXml;
        }
    }
    else
    {
        if (string.IsNullOrWhiteSpace(retornoXml.InnerText))
        {
            throw new Exception("A propriedade InnerText do XML retornado pelo webservice está vazia.");
        }

        RetornoServicoString = retornoXml.InnerText;

        //Remover do XML retornado o conteúdo <?xml version="1.0" encoding="utf-8"?> ou gera falha na hora de transformar em XmlDocument
        if (RetornoServicoString.IndexOf("?>") >= 0)
        {
            RetornoServicoString = RetornoServicoString.Substring(RetornoServicoString.IndexOf("?>") + 2);
        }

        //Remover quebras de linhas
        RetornoServicoString = RetornoServicoString.Replace("\r\n", "");
    }

    if (soap.PadraoNFSe == PadraoNFSe.FIORILLI || soap.PadraoNFSe == PadraoNFSe.SONNER || soap.PadraoNFSe == PadraoNFSe.SMARAPD || soap.PadraoNFSe == PadraoNFSe.DSF)
    {
        RetornoServicoString = RetornoServicoString.Replace("ns1:", string.Empty);
        RetornoServicoString = RetornoServicoString.Replace("ns2:", string.Empty);
        RetornoServicoString = RetornoServicoString.Replace("ns3:", string.Empty);
        RetornoServicoString = RetornoServicoString.Replace("ns4:", string.Empty);
    }
    else if (soap.PadraoNFSe == PadraoNFSe.SIMPLE)
    {
        RetornoServicoString = RetornoServicoString.Replace("m:", string.Empty);
    }

    RetornoServicoXML = new XmlDocument
    {
        PreserveWhitespace = false
    };
    RetornoServicoXML.LoadXml(RetornoServicoString);
}

I comment the original catch to find the problem, but I didn't have any luck.

Here is the Xmldocument.OuterXml from the first parameter:

<?xml version="1.0" encoding="utf-8"?>
<consStatServNFCom versao="1.00" xmlns="http://www.portalfiscal.inf.br/nfcom">
    <tpAmb>2</tpAmb>
    <xServ>STATUS</xServ>
</consStatServNFCom>

Here is the Servico object (WebString Soap):

Web URL = http://www.portalfiscal.inf.br/nfcom/wsdl/NFComStatusServico  
Content Type = application/soap+xml; charset=utf-8;  
Return Tag = nfcomResultMsg  
Soap String = <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><nfcomDadosMsg xmlns="http://www.portalfiscal.inf.br/nfcom/wsdl/NFComStatusServico">{xmlBody}</nfcomDadosMsg></soap:Body></soap:Envelope>

I tried to research this issue, but everything that I read, was form, at least, 3 years ago and have other causes that I having no problems with.

I am still watching the videos from IAmTimCorey, to learn C# and try to figured out how can I find the problem. The last video I saw was about Handling Exceptions and help me with StackTrace and InnerExeption, that I didn't knew about.

At first I think, maybe, was something wrong with my public configuration, so, I installed IIS (from Windows Features) in my laptop to try simulate the error, but I had no success.

I also read Microsoft documentation about IIS, HttpWebRequest and others methods that showed in my research, but I can't figured out a relation between IIS environment and HttpWebRequest problem.

Here is my web.config content. Besides stdoutLogEnable is true, this error generates no logs.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\NFeModelo62Api.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
    </system.webServer>
  </location>
</configuration>
<!--ProjectGuid: 4c7ebfbf-36d8-47ca-bc46-a62f36c09fa6-->

Solution

  • I found the solution, after remake my API from scratch with just the service I was having problem. I decided to create a simple scenario to investigating this issue.

    After some other issues in the way, I finally get the same error before with dotnet-wtrace inside the application folder in the staging server:

    Failed to determine the https port for redirect.

    C:\inetpub\wwwcore\NFComModelo62\> dotnet-wtrace --handlers aspnet .\NFeModelo62Api.exe http://localhost/NFeModelo62Getway/v1/getStatus62
    

    I found the solution in this Stack Overflow post Failed to determine the https port for redirect

    I my case, I changed the property Load User Profile to true in IIS Application Pool Advanced Configuration Options. I showing a print screen bellow, but my Windows is not in english, it is just for reference.

    IIS Application Pool Advanced Configurtion Screen