2013-01-22 21 views
25

Sto scrivendo un'applicazione API Web ASP.NET che richiede di accettare un caricamento di file e inoltrarlo a un altro endpoint HTTP.Supporto WebAPI Supporto streaming

Sono preoccupato del fatto che se molti utenti provano a caricare un file da 100 MB ciascuno (che è un caso d'uso valido) la mia applicazione avrà un ingombro di memoria elevato e, a seconda del volume di richieste di grandi dimensioni, questo ingombro potrebbe diventare grande e la mia applicazione si rovescia e muore.

Idealmente mi piacerebbe iniziare lo streaming del file verso l'altro endpoint HTTP non appena il server web inizia a ricevere il file per ridurre significativamente il carico sul server.

Sono sicuro che questo processo ha un nome ma non lo so, il che sta rendendo la ricerca piuttosto difficile.

Ho eseguito un po 'di lavoro con Response Streaming nell'API Web, ma non ho mai dovuto considerare lo streaming richieste prima.

migliore che posso dire che ho bisogno di capire come:

  • iniziare ad elaborare il flusso prima che sia terminato il caricamento.
  • Utilizzare HttpClient per eseguire lo streaming della stessa richiesta per lo streaming degli stessi dati sull'altro endpoint HTTP.

Qualcuno può offrirmi alcune indicazioni?

+1

Che tipo di utilizzo di MultipartStreamProvider è stato reso possibile? Sto lottando per ottenere la stessa identica cosa ... Potresti condividere il codice del tuo controller? – Bredstik

risposta

38

Questa è una domanda interessante. Proverò a fare del mio meglio per dare alcuni suggerimenti generali.

alcune cose da considerare:

1) Web API di buffer di default le richieste in modo che il timore che l'occupazione di memoria potrebbe essere considerevole è sicuramente giustificata. È possibile forzare API Web di lavorare con le richieste in modalità streaming:

public class NoBufferPolicySelector : WebHostBufferPolicySelector 
    { 
     public override bool UseBufferedInputStream(object hostContext) 
     { 
      var context = hostContext as HttpContextBase; 

      if (context != null) 
      { 
      if (string.Equals(context.Request.RequestContext.RouteData.Values["controller"].ToString(), "uploading", StringComparison.InvariantCultureIgnoreCase)) 
       return false; 
      } 

      return true; 
     } 

     public override bool UseBufferedOutputStream(HttpResponseMessage response) 
     { 
      return base.UseBufferedOutputStream(response); 
     } 
    } 

e quindi sostituire il servizio:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHostBufferPolicySelector), new NoBufferPolicySelector()); 

Si prega di notare che a causa di differenze tra WebHost e SelfHost a questo punto, tale cambiamento è possibile solo su WebHost. Se il punto finale è selfHosted, si dovrà impostare la modalità di streaming a livello GlobalConfig:

//requests only 
selfHostConf.TransferMode = TransferMode.StreamedRequest; 
//responses only 
selfHostConf.TransferMode = TransferMode.StreamedResponse; 
//both 
selfHostConf.TransferMode = TransferMode.Streamed; 

ho bloggato sulla gestione di file di grandi dimensioni in API Web più in dettaglio prima - http://www.strathweb.com/2012/09/dealing-with-large-files-in-asp-net-web-api/ quindi spero vi accorgerete che la utile.

2) In secondo luogo, se si utilizza HttpClient, in .NET 4 bufferizza il corpo delle richieste per impostazione predefinita, quindi è consigliabile utilizzare .NEt 4.5.

Se si deve utilizzare .NET 4 si deve lavorare con HttWebRequest direttamente: - http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowreadstreambuffering.aspx - http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowwritestreambuffering.aspx

3) Per quanto riguarda spingere i dati al client che è sicuramente possibile se si vuole fallo con PushStreamContent. Henrik ha un breve post introduttivo qui - http://blogs.msdn.com/b/henrikn/archive/2012/04/23/using-cookies-with-asp-net-web-api.aspx (è basato sul Web API bit RC quindi potrebbe essere necessario modificare alcune firme etc.) Ho anche bloggato su spingendo blocchi di dati di flusso qui - http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/

EDIT: Per vedere un esempio di PushStreamContent nella richiesta, è possibile dare un'occhiata a questa soluzione di esempio - http://aspnet.codeplex.com/SourceControl/changeset/view/bb167f0b0013#Samples/Net45/CS/WebApi/UploadXDocumentSample/ReadMe.txt

+0

Non mi ero reso conto che sarei stato in grado di utilizzare PushStreamContent durante l'emissione di una richiesta. Li ho sempre usati solo in una risposta. Fortunatamente stiamo usando .NET 4.5 - quindi vuol dire che HttpClient non bufferizza le richieste? –

+0

Sì: HttpClient in .NET 4.5 non esegue il buffer delle richieste per impostazione predefinita. In .NET 4 fa (significa carica l'intera richiesta in memoria, quindi invia). –

+0

Ho aggiunto un altro riferimento di esempio nella risposta (PushStreamContent nella richiesta) –