2015-11-24 39 views
6

Nel tentativo di migrare un progetto Web api (classico progetto web.config), utilizzare PushStreamContent per l'ultima app Web asp.net 5 (project.json).PushStreamContent in asp.net 5/mvc 6 non funziona

Il mio problema è che non riesco a far funzionare PushStreamContent.

Quando uso questo controller api - di conseguenza finirà in un formato JSON e non come un flusso:

[Route("api/[controller]")] 
public class EventsController : Controller 
{ 
    private static readonly ConcurrentQueue<StreamWriter> s_streamWriter = new ConcurrentQueue<StreamWriter>(); 

    [HttpGet] 
    public HttpResponseMessage Get(HttpRequestMessage request) 
    { 
     HttpResponseMessage response = request.CreateResponse(); 
     response.Content = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteToStream), "text/event-stream"); 
     return response; 
    } 

    private void WriteToStream(Stream outputStream, HttpContent headers, TransportContext context) 
    { 
     var streamWriter = new StreamWriter(outputStream) {AutoFlush = true}; 
     s_streamWriter.Enqueue(streamWriter); 
    } 
} 

Se cambio l'azione di controllo per restituire un compito e avvolgere PushStreamContent in un MyPushStreamResult di classe - Ti piace questa:

[HttpGet] 
public async Task<IActionResult> Get(HttpRequestMessage request) 
{ 
    var stream = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteToStream), "text/event-stream"); 
    return new MyPushStreamResult(stream, "text/event-stream"); 
} 

public class MyPushStreamResult : ActionResult 
{ 
    public string ContentType { get; private set; } 
    public PushStreamContent Stream { get; private set; } 
    public MyPushStreamResult(PushStreamContent stream, string contentType) 
    { 
     Stream = stream; 
     ContentType = contentType; 
    } 
    public override async Task ExecuteResultAsync(ActionContext context) 
    { 
     var response = context.HttpContext.Response; 
     response.ContentType = ContentType; 
     await Stream.CopyToAsync(response.Body); 
    } 
} 

una richiesta alla mia azione di controllo è ora di tornare un ruscello, ma il flusso non si scarichi prima che vicino sul lato server o contiene un sacco di dati. Quando spingo i dati sul flusso di output di PushStreamContent, scarico dopo ogni scrittura di testo, ma suppongo che lo svuotamento non sia sulla risposta. Streaming.

Cosa mi manca? Non riesco a trovare campioni con la struttura di asp.net 5.

+1

la funzione 'IHttpBufferingFeature' può essere d'aiuto, hai provato a disabilitare il buffering? –

+0

sembra che "IHttpBufferingFeature' non sia supportato in Kestrel [docs] (http://docs.asp.net/en/latest/fundamentals/servers.html#supported-features-by-server) –

+0

Nel primo esempio non scrivi mai allo stream. – usr

risposta

4

HttpResponseMessage non viene trattato in modo particolare in ASP.NET 5 a meno che non si utilizzi il pacchetto Microsoft.AspNet.Mvc.WebApiCompatShim. Questo pacchetto è non consigliato se è possibile utilizzare le funzionalità di ASP.NET 5 per fare cose simili ed è stato creato per supportare la compatibilità con le versioni precedenti.

Quindi, dal momento HttpResponseMessage non viene considerato speciale, il suo essere reso come JSON dal JsonOutuptFormatter come qualsiasi altro oggetto .NET

Invece di PushStreamContent, attualmente si dispone l'accesso a flusso di risposta direttamente via HttpContext.Response.Body proprietà, in modo da puoi scrivere direttamente nello stream.

Aggiornato:
PushStreamContent in API Web permesso di scrivere direttamente al flusso di risposta. Questo tipo è stato creato (dal team API Web e non è presente come parte della libreria System.Net.Http in cui sono presenti tutti gli altri tipi di contenuto) in modo che si possa scrivere direttamente nello stream, ad esempio, da un controller o filtro ecc. L'alternativa a PushStreamContent era StreamContent che consentiva solo di fornire un oggetto Stream e quindi i livelli host "copiavano" i dati dal flusso di origine (come i dati di "pull"). Anche PushStreamContent non è niente di speciale da solo. Si potrebbe scrivere il proprio tipo che deriva da HttpContent.

Per riepilogare, PushStreamContent è consentito scrivere sul flusso di risposta direttamente dove, come in ASP.NET 5, abbiamo accesso diretto allo stream e quindi è possibile scrivere su di esso.

Aggiornato:
Alla forma molto semplice (a destra, si potrebbe convertire in ActionResult per testabilità), il seguente dovrebbe funzionare.

[HttpGet] 
public Task Get() 
{ 
    HttpContext.Response.ContentType = "text/event-stream"; 
    var sourceStream = // get the source stream 
    return sourceStream.CopyToAsync(HttpContext.Response.Body); 
} 
+0

'PushStreamContent' è usato per scrivere più volte nello stream, come una chat in cui il server può inviare nuovi dati al client. Non riesco a vedere come posso scrivere più volte su 'HttpContext.Response.Body'. Puoi fare un esempio? –

+0

Ho aggiornato il mio post con ulteriori dettagli. –

+0

Ho letto il tuo aggiornamento e ho provato diverse cose. Ma non riesco a farlo funzionare e non riesco a trovare alcun esempio di codice scritto in asp.net 5, ma restituisco un flusso al client, il server può scrivere singoli blocchi di dati. Puoi fare un esempio di progetto/codice snippet? –

Problemi correlati