2014-05-12 13 views
7

Ho un servizio WCF (webHttpBinding) di tipo host autonomo. La maggior parte dei metodi restituisce la versione xml o json degli oggetti al client.Come posso eseguire lo streaming di una risposta da WCF senza buffering?

Ho un paio di metodi GET che attivano metodi a esecuzione prolungata e mi piacerebbe trasmettere la risposta del registro al browser (o all'applicazione) in modo che l'utente sappia cosa sta succedendo. Questo sarebbe semplice da realizzare con HttpContext.Current.Response.OutputStream.Write. Sfortunatamente, HttpContext.Current è sempre nullo in un servizio WCF auto-ospitato, anche se includo la configurazione aspNetCompatibilityEnabled (IIS non è un'opzione purtroppo).

ho provato AnonymousPipeServerStream: WCF and streaming requests and responses

insieme prima impostazione:

OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse; 
context.ContentType = "text/plain"; 

in modo che la risposta arriva nel browser che non scarica il flusso in un file da salvare.

In Chrome non funziona affatto, si blocca fino alla fine. In IE o wget sembra buffer per circa 4k (o qualcosa) alla volta. Questo non va bene per la registrazione, a meno che non sputi un sacco di messaggi di log non necessari per forzare l'output, l'utente non sa veramente cosa sta succedendo. Posso solo supporre che ciò sia dovuto al fatto che la risposta è in realtà una risposta frammentata e che i blocchi sono 4k (anziché solo scrivere sull'output).

La correzione per ottenere il chrome all'output è apparentemente di scrivere dei rifiuti nel contenuto prima di inviare la risposta chunked: Chunked transfer encoding - browser behavior, tuttavia, non penso sia possibile con WCF.

Così, le possibili soluzioni sto cercando:

  • Un modo di scrivere al OutputStream in WCF in un servizio in hosting di sé (senza IIS). o
  • Un modo per controllare le dimensioni del blocco in una risposta di flusso (& un modo per scrivere prima alcuni contenuti in modo che Chrome esegua il rendering dei blocchi).

Un'altra opzione, suppongo, è di abbandonare WCF in favore di qualcosa di più REST-friendly (sto iniziando a pensare che il WCF non fosse la scelta giusta). Tuttavia, avendo scritto così tanto in WCF ora, questo sembra un compito noioso. A meno che non ci sia qualcosa su cui posso passare, sarebbe una migrazione facile (ad esempio se potessi riutilizzare le stesse classi di servizio, magari con solo attributi diversi). Nancy forse?

risposta

2

Ho fatto qualcosa di simile a quello che stai chiedendo qui - anch'esso ospitato da me. Ho scritto un servizio WCF (BasicHttpBinding) che eseguiva sia lo streaming che il buffering dei dati sui dispositivi client che utilizzavano il mio servizio per la sincronizzazione dei dati. Lo streaming è difficile, come probabilmente avete capito, e non penso che ci sia un modo per "scrivere nel flusso".

In un certo senso di base, lo streaming su un servizio WCF funziona allo stesso modo che funziona File.IO, come si vede nel seguente codice

FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); 
BinaryReader br = new BinaryReader(fs); 

Se il file in questione è di 1 GB, il vostro filestream inizierà restituendo i byte prima della lettura alla fine del file. Lo streaming su WCF funziona allo stesso modo (infatti, implementa FileStream, nella mia esperienza), motivo per cui è utile per enormi quantità di dati. Legge ... invia; legge ... invia. Quindi non sono sicuro di come iniettare alcune informazioni in quel flusso per l'output sul tuo schermo.

Detto questo, la nostra interfaccia utente di sincronizzazione mostra il conteggio dei byte che scendono, più la percentuale completa, per impedire agli utenti di spegnere la macchina o annullare. Lo facciamo da avere un thread separato legge la dimensione del file di download ogni 10 secondi e calcolando la percentuale di tutto (il formato completo è inviare indietro come un parametro nella risposta), quindi scrivere i risultati verso la finestra dei risultati UI . Quindi la soluzione è in realtà piuttosto semplice, nel nostro caso.

+0

Quindi, secondo te, quello che sto cercando di fare proprio non è possibile? – David

+0

Suppongo che dipenda da cosa stai provando a trasmettere. Sono dati grezzi che stai spostando da un posto all'altro? Lo streaming viene solitamente utilizzato per enormi set di dati (ad esempio, trasmettiamo musica e film da Amazon) e una volta avviato lo streaming, il client e l'host si trovano a un passo, l'invio e la ricezione fino al termine del processo. Non sono sicuro di come o perché vorresti iniettare qualcosa in quel tipo di flusso. Se sei preoccupato per il tuo utente che fa qualcosa di strano perché non vede progressi, ci sono modi (come descrivo) attorno a quel problema. – Brian

+0

Sto provando a trasmettere le informazioni di registrazione (vedere OP). Quindi la quantità di dati potrebbe variare da poche righe (se le cose vanno bene) a 1000s di linee se le cose vanno male. Questo è qualcosa che ho fatto in passato senza problemi scrivendo sul flusso di output (in .NET e in altri linguaggi), ma il problema sembra essere che WCF non mi dà la flessibilità che sto cercando. – David

0

Io file di streaming come questo:

Gruppo i metodi che restituisce i dati che deve essere in streaming in un endpoint e quindi aggiungere il transferMode streaming su questo endpoint.

Ecco la configurazione che utilizzo (per basicHttpBinding).

<services> 
    <service name="CustomersService"> 
    <endpoint address="FilesService.svc" binding="basicHttpBinding" bindingConfiguration="StreamedBinding" contract="Soap.Interfaces.IFilesService" /> 
    </service> 
</services> 

e definire la configurazione di legame:

<bindings> 
    <basicHttpBinding> 
     <binding name="IntersolveWebServicesStreamedBinding" allowCookies="true" transferMode="Streamed" maxReceivedMessageSize="67108864" /> 
    </basicHttpBinding> 
</bindings> 

In sostanza, è necessario impostare il transferMode nella configurazione di legame.

Non l'ho provato con webHttpBinding, quindi per favore fatemi sapere se funziona per voi.

+0

Sì, ho provato questo (vedi OP) – David

0

Basta ingannare il browser a pensare ci sia una risposta HTML con il Multipart Content-Type

http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html

Ho usato questo per un bel paio di cose tra cui MJPEG, ma si può anche utilizzare per COMET/WebSocket come risposte .

+0

Ho provato questo, ma WCF sembra prendere il controllo di quanti dati sono memorizzati nella risposta chunked. Il tipo di contenuto "text/plain" che menziono nel PO ha lo stesso impatto. – David

Problemi correlati