System.Net.HttpWebRequest genera diverse richieste WebExceptionStatus per le richieste SSL e non SSL in condizioni speciali

Questo articolo illustra come risolvere il problema in cui vengono generati diversi WebExceptionStatus quando si usa la System.Net.HttpWebRequest classe .

Versione originale del prodotto: .Net Framework
Numero KB originale: 2007873

Sintomi

Si usa la System.Net.HttpWebRequest classe di Microsoft .Net Framework per inviare una richiesta HTTP (Hypertext Transfer Protocol) o Hypertext Transfer Protocol Secure (HTTPS) a un server. Questa richiesta richiede tempo per ricevere una risposta dal server. Durante questo tempo di attesa, se l'ora dell'orologio di sistema viene aumentata manualmente o se l'orologio di sistema si ritarda indietro e quindi il servizio Ora di Windows si adatta all'ora locale effettiva, si verifica uno degli scenari seguenti:

Per una richiesta inviata tramite HTTP non crittografato, la System.Net.HttpWebRequest classe genererà l'eccezione seguente:

La richiesta è stata interrotta: l'operazione è scaduta.

Inoltre, la Status proprietà nell'oggetto generato WebException indicherà il valore WebExceptionStatus.Timeout.

Per una richiesta inviata tramite HTTPS, la System.Net.HttpWebRequest classe genererà una delle eccezioni seguenti:

Connessione sottostante chiusa: Errore imprevisto durante un'operazione di ricezione.

Inoltre, la Status proprietà nell'oggetto generato WebException indicherà il valore WebExceptionStatus.ReceiveFailure.

oppure

La connessione sottostante è stata chiusa: una connessione che doveva essere mantenuta attiva è stata chiusa dal server .

Inoltre, la Status proprietà nell'oggetto generato WebException indicherà il valore WebExceptionStatus.KeepAliveFailure.

In tutti gli scenari precedenti, che viene intercettata ha la InnerException proprietà . Se si intercetta e WebException si fa riferimento alla WebException.InnerException.InnerException proprietà , si noterà che per tutti i casi precedenti, la Message stringa indicherà:

Non è possibile stabilire la connessione. Risposta non corretta della parte connessa dopo un intervallo di tempo oppure mancata risposta dall'host collegato.

Questo messaggio è l'interpretazione dettagliata del codice di errore Winsock 10060 = WSAETIMEDOUT.

Pertanto, quando l'ora di sistema viene aumentata manualmente, Winsock genera correttamente l'errore di timeout 10060, ma viene eseguito il wrapping come tipi di eccezione diversi per le richieste SSL (Secure Sockets Layer) e non SSL.

In circostanze di timeout normali in cui l'ora di sistema non viene manomessa, gli scenari SSL e non SSL riflettono correttamente lo WebExceptionStatus.Timeout stato e generano l'eccezione comune: l'operazione è scaduta.

Motivo

Quando si effettua la richiesta tramite SSL o non SSL, la System.Net.ServicePointManager classe assegnerà la richiesta a una connessione interna, che alla fine effettuerà la connessione Winsock. Nel caso di richieste SSL, questa richiesta o connessione passa attraverso un'altra classe SSL/TLS interna, responsabile della crittografia o decrittografia dei dati. Per le connessioni non SSL, questa classe SSL/TLS interna non è affatto coinvolta.

Quando l'ora viene modificata e viene rilevata l'eccezione a livello winsock, questo errore deve ora spostarsi verso l'alto da Winsock al livello dell'applicazione. Per le connessioni non SSL, questa eccezione viene rilevata direttamente dalla classe di connessione interna, ma per le richieste SSL, questo errore viene gestito dalla classe SSL/TLS interna. Questa classe considera questo errore non SSL come o ReceiveFailureKeepAliveFailure e pertanto ha uno stato di eccezione diverso, mentre per la connessione non SSL l'errore viene eseguito correttamente perché viene gestito da una classe diversa.

stato

Questo comportamento è predefinito.

Risoluzione

Per risolvere questa discrepanza dei tipi di eccezione generati in questa condizione speciale in cui l'ora di sistema viene manomessa, l'applicazione deve intercettare WebException e quindi fare riferimento alla WebException.InnerException.InnerException.Message proprietà.

Se la Message stringa è uguale all'errore dettagliato winsose equivalente a 10060 = WSAETIMEDOUT, è possibile considerare o ReceiveFailureKeepAliveFailure come timeout regolare e non considerarlo come o ReceiveFailureKeepAliveFailure.

L'applicazione può usare la soluzione alternativa seguente al momento dell'esecuzione catch() di WebException per una versione inglese del framework. Per una versione localizzata del framework, la soluzione alternativa seguente deve essere modificata in base alla localizzazione della lingua.

Importante

Questo codice di esempio viene fornito così come è ed è destinato solo a scopi di esempio. Viene fornito senza garanzie e non conferisce alcun diritto.

try
{
    ......
}
catch (WebException oWEx)
{
    WebExceptionStatus oStatus = oWEx.Status;
    String strTimeoutErrorMessage = "A connection attempt failed because the connected party did not properly respond "
                                  + "after a period of time, or established connection failed because connected host has failed to respond";
    switch (oStatus)
    {
        case WebExceptionStatus.KeepAliveFailure:
            if ((oWEx.InnerException != null) && (oWEx.InnerException.InnerException != null)
                && oWEx.InnerException.InnerException.Message.ToString().Equals(strTimeoutErrorMessage, StringComparison.CurrentCultureIgnoreCase))
            {   //----------------------------------------------------------------------
                // This is Timeout Error which is wrongly thrown as a ReceiveFailure for
                // SSL requests under this special condition.
                //
                // Handle this as a Timeout Error
                //----------------------------------------------------------------------
            }
            else
            {
                //----------------------------------------------------------------------
                // This is truly a KeepAliveFailure.
                //----------------------------------------------------------------------
            }
            break;
        case WebExceptionStatus.Timeout:
             //----------------------------------------------------------------------
             // This is a Timeout.
             //----------------------------------------------------------------------
             break;
        case WebExceptionStatus.ReceiveFailure:
            if ((oWEx.InnerException != null)
                && (oWEx.InnerException.InnerException != null)
                && oWEx.InnerException.InnerException.Message.ToString ().Equals (strTimeoutErrorMessage, StringComparison.CurrentCultureIgnoreCase))
            {    //----------------------------------------------------------------------
                 // This is Timeout Error which is wrongly thrown as a ReceiveFailure for
                 // SSL requests under this special condition.
                 //
                 // Handle this as a Timeout Error
                 //----------------------------------------------------------------------
            }
            else
            {    //----------------------------------------------------------------------
                 // This is truly a ReceiveFailure.
                 //----------------------------------------------------------------------
            }
            break;
        default:
               //----------------------------------------------------------------------
               //  This is some other Exception
               //----------------------------------------------------------------------
            break;
    }
}