Domanda

Ho problemi a leggere una risposta "in blocchi" quando utilizzo uno StreamReader per leggere il flusso restituito da GetResponseStream() di un HttpWebResponse:

// response is an HttpWebResponse
StreamReader reader = new StreamReader(response.GetResponseStream());
string output = reader.ReadToEnd(); // throws exception...

Quando il reader.ReadToEnd() si chiama il metodo e ricevo la seguente System.IO.IOException: Impossibile leggere i dati dalla connessione di trasporto:La connessione è stata chiusa.

Il codice precedente funziona perfettamente quando il server restituisce una risposta "non frammentata".

L'unico modo in cui sono riuscito a farlo funzionare è utilizzare HTTP/1.0 per la richiesta iniziale (invece di HTTP/1.1, l'impostazione predefinita), ma sembra una soluzione inefficace.

Qualche idea?


@Mandrino

La tua soluzione funziona piuttosto bene.Genera ancora la stessa IOExeception sull'ultima Read().Ma dopo aver esaminato il contenuto di StringBuilder sembra che tutti i dati siano stati ricevuti.Quindi forse devo solo racchiudere Read() in un try-catch e ingoiare l'"errore".

È stato utile?

Soluzione

Non l'ho provato con una risposta "a blocchi", ma qualcosa di simile funzionerebbe?

StringBuilder sb = new StringBuilder();
Byte[] buf = new byte[8192];
Stream resStream = response.GetResponseStream();
string tmpString = null;
int count = 0;
do
{
     count = resStream.Read(buf, 0, buf.Length);
     if(count != 0)
     {
          tmpString = Encoding.ASCII.GetString(buf, 0, count);
          sb.Append(tmpString);
     }
}while (count > 0);

Altri suggerimenti

Sto lavorando su un problema simile.HttpWebRequest e HttpWebRequest .net gestiscono cookie e reindirizzamenti automaticamente, ma non gestiscono automaticamente il contenuto in blocchi nel corpo della risposta.

Ciò è forse dovuto al fatto che il contenuto suddiviso in blocchi può contenere più di semplici dati (ad esempio:nomi di blocchi, intestazioni finali).

Leggere semplicemente lo stream e ignorare l'eccezione EOF non funzionerà poiché lo stream contiene più del contenuto desiderato.Lo stream conterrà blocchi e ogni blocco inizia dichiarando la propria dimensione.Se il flusso viene semplicemente letto dall'inizio alla fine, i dati finali conterranno i metadati del blocco (e nel caso in cui si tratti di contenuto compresso con gzip, fallirà il controllo CRC durante la decompressione).

Per risolvere il problema è necessario analizzare manualmente il flusso, rimuovendo la dimensione del pezzo da ciascun pezzo (così come i delimitatori CR LF), rilevando il pezzo finale e mantenendo solo i dati del pezzo.Probabilmente c'è una libreria là fuori da qualche parte che fa questo, non l'ho ancora trovata.

Risorse utili:

http://en.wikipedia.org/wiki/Chunked_transfer_encoding http://tools.ietf.org/html/rfc2616#section-3.6.1

Craig, senza vedere lo stream che stai leggendo è un po' difficile eseguire il debug ma FORSE potresti cambiare l'impostazione della variabile count in questa:

count = resStream.Read(buf, 0, buf.Length-1);

È un po' un trucco, ma se l'ultima lettura ti sta uccidendo e non restituisce alcun dato, in teoria questo eviterà il problema.Mi chiedo ancora perché lo streaming stia facendo questo.

Ho avuto lo stesso problema (ed è così che sono finito qui :-).Alla fine è stato possibile risalire al fatto che il flusso in blocchi non era valido: mancava il blocco finale di lunghezza zero.Ho creato il seguente codice che gestisce flussi in blocchi sia validi che non validi.

using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
    StringBuilder sb = new StringBuilder();

    try
    {
        while (!sr.EndOfStream)
        {
            sb.Append((char)sr.Read());
        }
    }
    catch (System.IO.IOException)
    { }

    string content = sb.ToString();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top