2012-07-29 11 views
17

Questo è un problema che ho indagato nell'ultima settimana e non riesco a trovare alcuna soluzione. Ha trovato post chiedendo la stessa cosa ma senza ottenere una risposta, sperando che questo possa aiutare anche gli altri.Come interrompere un flusso dal servizio WCF senza leggerlo per terminare?

Ho un servizio WCF che restituisce un oggetto contenente un stream al suo interno. Io uso basicHttpBinding con trasferimento in streaming e Mtom per inviarlo al client.

cliente chiama il servizio WCF e chiude immediatamente dopo il proxy riceve l'oggetto risposta.

Successivamente, il client legge lo stream ricevuto dal servizio WCF e lo scrive in un file sul disco locale. Tutto questo funziona bene.

Il mio problema si verifica quando il client desidera interrompere l'operazione e interrompere il download dei dati dal servizio WCF. Se chiamo .close() sullo stream, ad esempio: serverReply.DataStream.Close();, blocca e legge l'intero flusso dal servizio WCF fino alla sua fine prima di continuare. Lo stream può essere abbastanza grande e la rete non è sempre veloce.

Questo è molto indesiderabile sia per l'utilizzo delle risorse di rete, che è fondamentalmente sprecato per i dati che non ha più alcun utilizzo. E poiché basicHttpBinding consente solo due connessioni TCP simultanee (per impostazione predefinita) al server di servizio WCF, blocca altri tentativi di connessione finché il flusso non viene letto fino alla fine.

mi potrebbe aumentare il numero di connessioni simultanee, ma sarebbe una cattiva soluzione come sarebbe creare un'apertura di guai.

Ad esempio, 20 download interrotti che stanno ancora scaricando i dati per buttarlo via. Devo interrompere completamente il trasferimento.

Sul client, l'oggetto flusso è solo una normale classe Stream, quindi ha solo il metodo close, nient'altro.

Chiamare .close() o .abort() sull'oggetto proxy non aiuta, non lo distrugge utilizzando .dispose() o qualsiasi altro metodo. Sul lato server, gestisco l'evento OperationContext.OperationCompleted, ma non viene attivato finché i dati dallo stream non vengono letti fino alla fine.

Quindi la domanda è: come posso chiudere/interrompere lo streaming senza leggerlo interamente?

+0

Qualche fortuna con questo? – Schultz9999

+0

Soffrendo dello stesso problema durante l'invio di file molto grandi ... sembra che manchi qualcosa di veramente ovvio. probabilmente dovrò implementare il chunking come soluzione alternativa. –

risposta

0

Hai provato a giocare con binding.MaxBufferSize?
Hai provato a giocare con le impostazioni del file app.config per esempio:

<bindings> 
    <wsHttpBinding> 
    <binding name="default" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" 
      closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" > 
     <readerQuotas maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" 
        maxDepth="64" maxStringContentLength="2147483647" /> 
    </binding> 

    </wsHttpBinding> 
</bindings> 

vorrei ridurre al minimo i timeout anf tampone lunghezze e cercare di interrompere o chiudere e vedere cosa succede.

+1

L'ho provato ma non aiuta. Una volta che il server inizia a inviare il flusso, non si ferma finché non viene ricevuto tutto dal client. Chiusura del proxy non fa nulla. È come se non ci fosse modo apparente di fermare la comunicazione. Quando il client interrompe la lettura del flusso, posso vedere tcp window zero tornare al server. E il server invia periodicamente un probe zero della finestra per verificare se il client è pronto per la lettura. E naturalmente il client rinvia nuovamente la finestra zero. Questo va avanti all'infinito finché il processo non viene ucciso. – Yev

+0

Hai provato a leggere il flusso utilizzando solo la classe HttpClient e hai visto se potevi chiudere lo stream? –

+0

Come posso farlo senza chiamare un servizio WCF? Ho fatto qualche ricerca in più e sembra che non ci sia modo di chiudere lo stream dal lato client. Ho provato un approccio diverso. Ho creato un altro servizio, un servizio di controllo, e ho provato a chiudere il flusso da lì (lato server). Ma senza fortuna. Qualcosa non funziona, non chiude o non dispone. – Yev

1

Dopo indagini ho scoperto che il cliente WCF sarà continuare a leggere dal flusso fino CloseTimeout ellapsed, allora sarà interrompere il collegamento. Potresti ridurre closeTimeout sul client per minimizzare il problema.

NOTA: è necessario includere il codice che dispone uno stream nel blocco try/catch. Il metodo stream.Dispose() genererà TimeoutException che frena una linea guida di not throwing exceptions in Dispose method.

0

Penso che si stia semplicemente ricevendo il buffer dopo la chiusura. È necessario impostare maxBufferSize su un valore inferiore.

Si potrebbe anche voler limitare la quantità di dati letti sul server avvolgendo il flusso e sovrascrivendo la lettura. Utilizzare blocchi più piccoli se si dispone di un client con larghezza di banda ridotta e restituire un conteggio corrispondente dal metodo di lettura in modo che corrisponda all'importo effettivamente letto. Ciò limiterebbe il tasso di riempimento del buffer.

I miei test su questo argomento mi hanno coinvolto scrivendo un NeverEndingStream e restituendo sempre i dati. Ad un certo punto ho chiamato close sul client quindi quasi immediatamente la chiusura è stata richiamata sul server. Questo suggerisce che il buffer è stato semplicemente svuotato perché chiaramente non sarebbe mai stato in grado di leggere il mio stream fino alla fine.

Se si verificano ancora problemi, suggerisco di tenere traccia dei tempi del metodo di lettura sul flusso sottoposto a override. Se currentReadtime - the lastReadTime è> x, potresti chiamare Close e lanciare un'eccezione. Questo lo ucciderà di sicuro.

Problemi correlati