2013-11-27 18 views
8

Sto cercando di estendere il mio servizio REST (creato usando WCF/webHttpBinding) in modo che i client possano caricare dati compressi con gzip. Non sono sicuro di quale sia il modo migliore per farlo, ma ho pensato che sarebbe stato abbastanza semplice aggiungendo un modulo HTTP che decomprimerà i dati se Content-Encoding per la richiesta in arrivo è impostato su gzip.Posso modificare il contenuto di una richiesta HTTP in arrivo utilizzando un modulo HTTP?

Così ho creato una classe derivante dalla IHttpModule con la seguente implementazione:

private void OnBeginRequest(object sender, EventArgs e) 
    { 
    var app = (HttpApplication) sender; 
    var context = app.Context; 

    var contentEncoding = context.Request.Headers["Content-Encoding"]; 

    if (contentEncoding == "gzip") 
    { 
     // some debug code: 
     var decompressedStream = new GZipStream(context.Request.InputStream, CompressionMode.Decompress); 
     var memoryStream = new MemoryStream(); 
     decompressedStream.CopyTo(memoryStream); 
     memoryStream.Seek(0, SeekOrigin.Begin); 

     var streamReader = new StreamReader(memoryStream); 
     string msg = streamReader.ReadToEnd(); 

     context.Request.InputStream.Seek(0, SeekOrigin.Begin); 

     app.Request.Filter = //new TestFilterStream(app.Request.Filter); 
        new System.IO.Compression.GZipStream(
        app.Request.Filter, CompressionMode.Decompress); 
    } 

    } 

Il problema che sto vedendo è che la decompressione GZipStream non è mai effettivamente svolto. Ho confermato che i dati in arrivo sono in effetti gzip'd (la variabile msg contiene i dati corretti). Ho anche provato a creare la mia classe stream (TestFilterStream) sopra e assegnarla a app.Request.Filter e ho confermato che nessun membro della classe stream è effettivamente chiamato da ASP.NET. Quindi sembra che mentre è possibile specificare un filtro, quel filtro non sia effettivamente usato.

Non è effettivamente utilizzato HttpApplication.Request.Filter?

+0

hai provato a impostare 'Request.Filter' senza il tuo altro codice di debug? Potrebbe essere che tu abbia già letto il flusso della richiesta in modo che non applichi più il filtro. –

+0

Credo che non ci sia motivo di credere che Request.InputStream sia ricercabile. Probabilmente no. Prova a rimuovere il tuo codice di debug, probabilmente è comunque sbagliato (potresti dover chiudere/svuotare il decompressedStream prima che scriva veramente qualcosa nel flusso di memoria). – Luaan

+1

Si prega di limitare il problema, in quanto non è chiaro dalla domanda in cui si è verificato l'errore effettivo e quando. In realtà il problema è che 'GZipStream' non legge il flusso sottostante? È 'contentEncoding' euqual a' "gzip" ', viene chiamato il codice nel blocco' if'? Hai provato a registrare nel momento in cui viene chiamato questo metodo? Sei sicuro che il tuo modulo venga caricato? – CodeCaster

risposta

0

Ho appena eseguito un paio di test e il flusso Request.Filter viene chiamato, a condizione che esista un corpo della richiesta e che il gestore della richiesta venga letto dal gestore HTTP. Suppongo che tu usi un PUT o un POST, e certamente leggi il corpo della richiesta, quindi non dovrebbe essere un problema.

Sospetto che il commento di Knaģis sia corretto. Hai provato senza il codice di debug? Se analizzo la fonte HttpRequest, vedo una variabile _rawContent scritta esattamente una volta; allo stesso tempo vengono applicati i filtri delle richieste. Successivamente, il valore _rawContent viene semplicemente memorizzato nella cache e non viene mai aggiornato (né ripristinato quando viene aggiunto un filtro).

Quindi chiamando Request.InputStream nel codice di debug si impedisce definitivamente che il filtro venga applicato in seguito. Leggere la raccolta Request.Headers non è un problema.

2

ho provato a fissare la richiesta Filtro in due modi:

  1. Utilizzando un HttpModule
  2. Impostazione nella inizio di Application_BeginRequest() (Global.asax)

Sia con gli stessi risultati (VS2012 web project + IISExpress):

  • Se non ci sono dati di input (richiesta GET o simile), t egli Filter.Read non viene richiamato
  • In caso di un post con i dati reali, viene eseguito il filtro e il servizio web ottiene i dati filtrati
  • Anche se ho letto dal Request.InputStream prima che il filtro è impostato, ho ancora il filtro attivato dal mio codice di servizio.

Non ho un modo semplice di test con l'input Gzippet, quindi non ho provato se il filtro effettivo funziona. Tuttavia, so che si sta innescando, dal momento che ottengo un errore da GZipStream mentre tenta di cercare l'input.

Forse si stanno avendo altri HttpModules o filtri che interrompono il flusso di input o di controllo?

This post propone un metodo simile al vostro, ma anche afferma quanto segue, che può causare alcuni effetti collaterali (le mie prove non sono state usando WCF):

"Sembra che questo approccio innescare un problema in WCF, in quanto WCF si basa sulla lunghezza del contenuto originale e non sul valore ottenuto dopo la decompressione. "

0

Sei sicuro, che l'applicazione stessa dovrebbe preoccuparsi? Di solito viene gestito per configurazione di host (IIS). Quindi, in pratica, hai solo bisogno di implementare il supporto GZip personalizzato, quando fai da te il servizio. Puoi dare un'occhiata here