2012-07-29 11 views
17

Dies ist ein Problem, das ich in der letzten Woche untersucht habe und keine Lösung finden kann. Gefundene Beiträge, die dasselbe fragen, aber nie eine Antwort bekommen, hoffentlich hilft das auch anderen.Wie kann ich einen Stream vom WCF-Dienst abbrechen, ohne ihn zu Ende zu lesen?

Ich habe einen WCF Service, der ein Objekt zurückgibt, das eine stream darin enthält. Ich verwende basicHttpBinding mit Streaming-Übertragung und Mtom, um es an den Client zu senden.

Client ruft den Dienst WCF auf und schließt den Proxy sofort, nachdem er das Antwortobjekt empfangen hat.

Als Nächstes liest der Client den vom WCF-Dienst empfangenen Stream und schreibt ihn in eine Datei auf dem lokalen Datenträger. All das funktioniert gut.

Mein Problem ist, wenn der Client den Vorgang abbrechen und das Herunterladen der Daten vom WCF-Dienst beenden möchte. Wenn ich .close() im Stream aufrufen, z. B .: serverReply.DataStream.Close(); dann blockiert und liest es den gesamten Stream vom WCF-Dienst bis zu seinem Ende, bevor er fortfährt. Der Stream kann ziemlich groß sein und das Netzwerk ist nicht immer schnell.

Dies ist sehr unerwünscht für die Nutzung der Netzwerkressourcen, die im Grunde für Daten verschwendet wird, die nicht mehr verwendet werden. Und da basicHttpBinding nur zwei gleichzeitige TCP-Verbindungen (standardmäßig) zum WCF-Dienstserver zulässt, blockiert es andere Verbindungsversuche, bis der Stream bis zum Ende gelesen wird.

Ich könnte die Anzahl der gleichzeitigen Verbindungen erhöhen, aber das wäre eine schlechte Lösung, da es eine Öffnung für Probleme erstellen würde.

Zum Beispiel, 20 abgebrochene Downloads, die noch die Daten herunterladen, um es wegzuwerfen. Ich muss die Übertragung komplett stoppen.

Auf dem Client ist das Stream-Objekt nur eine reguläre Stream Klasse, also hat es nur die close-Methode, sonst nichts.

Das Aufrufen von .close() oder .abort() auf dem Proxy-Objekt hilft nicht, noch zerstört es mit .dispose() oder einer anderen Methode. Auf der Serverseite handle ich das OperationContext.OperationCompleted Ereignis, aber es wird nicht ausgelöst, bis die Daten von stream bis zum Ende gelesen werden.

Die Frage ist also, wie schließe ich den Stream, ohne ihn komplett zu lesen?

+0

Haben Sie Glück dabei? – Schultz9999

+0

Das gleiche Problem beim Senden von wirklich großen Dateien zu leiden ... scheint, als müsste etwas wirklich Offensichtliches fehlen. Ich werde wahrscheinlich Chunking als Workaround implementieren müssen. –

Antwort

0

Haben Sie versucht, mit binding.MaxBufferSize herumzuspielen?
Haben Sie mit Ihren app.config Datei Einstellungen ausprobiert spielen um z:

<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> 

ich die Timeouts anf Pufferlängen minimieren und versuchen würde, oder in der Nähe abbrechen und sehen, was passiert.

+1

Ich habe das versucht, aber es hilft nicht. Sobald der Server beginnt, den Stream zu senden, hört er nicht auf, bis er vom Client empfangen wurde. Das Schließen des Proxy tut nichts. Es ist, als ob es keine offensichtliche Möglichkeit gibt, die Kommunikation zu stoppen. Wenn der Client den Stream nicht mehr liest, kann ich TCP-Fenster Null zurück zum Server sehen. Und der Server sendet periodisch eine Fenster-Null-Prüfung, um zu sehen, ob der Client bereit ist, erneut zu lesen. Und natürlich sendet der Client wieder das Fenster Null zurück. Das geht ewig so lange, bis der Prozess beendet ist. – Yev

+0

Haben Sie versucht, den Stream nur mit der HttpClient-Klasse zu lesen und zu sehen, ob Sie den Stream schließen könnten? –

+0

Wie mache ich das, ohne einen WCF-Dienst aufzurufen? Ich habe etwas mehr Forschung und es scheint, dass es keine Möglichkeit gibt, den Stream von der Clientseite zu schließen. Ich habe einen anderen Ansatz versucht. Ich habe einen anderen Dienst, einen Kontrolldienst, erstellt und versucht, den Datenstrom von dort (Serverseite) zu schließen. Aber kein Glück. Etwas funktioniert einfach nicht, es schließt nicht oder entsorgt. – Yev

1

Nach der Untersuchung habe ich festgestellt, dass der WCF-Client aus dem Stream weiterlesen wird, bis closeTimeout erreicht ist, dann wird die Verbindung abgebrochen. Sie können closeTimeout auf dem Client verringern, um das Problem zu minimieren.

HINWEIS: Sie sollten den Code, der einen Stream enthält, in try/catch blockieren. Die stream.Dispose() - Methode löst eine TimeoutException aus, die eine Richtlinie von not throwing exceptions in Dispose method unterbricht.

0

Ich denke, Sie erhalten nur den Puffer nach dem Schließen. Sie sollten maxBufferSize auf einen niedrigeren Wert festlegen.

Sie möchten vielleicht auch die Menge der Daten begrenzen, die auf dem Server gelesen werden, indem Sie Ihren Stream und den überschreibenden Lesevorgang einschließen. Verwenden Sie kleinere Blöcke, wenn Sie einen Client mit geringer Bandbreite haben, und geben Sie eine entsprechende Anzahl von der read-Methode zurück, um der tatsächlich gelesenen Menge zu entsprechen. Dies würde die Füllrate des Puffers einschränken.

Meine eigenen Tests zu diesem Thema beteiligt mich Schreiben eines NeverEndingStream und immer Daten zurückgeben. Irgendwann habe ich dann auf dem Client gecalled und fast sofort wurde der Close auf dem Server aufgerufen. Dies deutet darauf hin, dass der Puffer nur geleert wurde, weil er meinen Stream niemals bis zum Ende lesen konnte.

Wenn weiterhin Probleme auftreten, empfehle ich Ihnen, das Timing der Read-Methode in Ihrem überschriebenen Stream zu verfolgen. Wenn currentReadtime - the lastReadTime> x ist, können Sie stattdessen Close aufrufen und eine Ausnahme auslösen. Das wird es sicher töten.

Verwandte Themen