WCF-und streaming-Anfragen und-Antworten
Ist es richtig, dass in WCF, ich kann nicht von einem service schreiben zu einem Bach, der vom client empfangen wurden?
Streaming wird unterstützt von der WCF für Anforderungen, Antworten oder beides.
Das möchte ich unterstützen ein Szenario, in dem der Daten-generator (entweder den client im Falle von Streaming-Anfrage, oder den server im Falle von Streaming-Antwort Schreiben können, der auf dem stream. Wird diese unterstützt?
Die Analogie ist die Antwort.Ausgabestrom von einem ASP.NET Anfrage. In ASPNET, jede Seite aufrufen kann Schreiben auf den Ausgabe-stream, und der Inhalt wird vom client empfangen. Kann ich etwas tun, ähnlich wie in einer WCF-service - aufrufen Schreiben auf einen stream, der vom client empfangen wurden?
Lassen Sie mich erklären, mit einem WCF-illustration. Das einfachste Beispiel für Streaming in WCF ist der service-Rücksendung eines FileStream auf einen client. Dies ist einer Streaming-Reaktion. Der server-code, um dies zu implementieren, ist wie folgt:
[ServiceContract]
public interface IStreamService
{
[OperationContract]
Stream GetData(string fileName);
}
public class StreamService : IStreamService
{
public Stream GetData(string filename)
{
return new FileStream(filename, FileMode.Open)
}
}
- Und der client-code ist so:
StreamDemo.StreamServiceClient client =
new WcfStreamDemoClient.StreamDemo.StreamServiceClient();
Stream str = client.GetData(@"c:\path\on\server\myfile.dat");
do {
b = str.ReadByte(); //read next byte from stream
...
} while (b != -1);
(Beispiel entnommen aus http://blog.joachim.at/?p=33)
Klar, oder? Gibt der server den Stream an den client, und der client ruft darauf zu Lesen.
Ist es möglich, den client an einen Bach, und dem server aufrufen auf ihm Schreiben?
In anderen Worten, anstatt ein pull-Modell - wo zieht der client Daten vom server - es ist ein push-Modell, bei dem der client stellt die "sink" - Strom und der server schreibt in Sie. Der server-seitige code könnte ungefähr so Aussehen:
[ServiceContract]
public interface IStreamWriterService
{
[OperationContract]
void SendData(Stream clientProvidedWritableStream);
}
public class DataService : IStreamWriterService
{
public void GetData(Stream s)
{
do {
byte[] chunk = GetNextChunk();
s.Write(chunk,0, chunk.Length);
} while (chunk.Length > 0);
}
}
Ist das möglich in der WCF ist, und wenn ja, wie? Was sind die config-Einstellungen, die erforderlich sind für die Bindung, interface, etc? Was ist Terminologie?
Vielleicht ist es nur Arbeit? (Ich habe es nicht ausprobiert)
Dank.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich bin ziemlich sicher, dass es keine Kombination von WCF-Bindungen, die Ihnen erlauben, um buchstäblich schreiben an die Clients streamen. Es scheint logisch, dass es angesichts der Tatsache, dass irgendwo unter der Oberfläche gibt es definitiv zu einem
NetworkStream
, aber sobald Sie beginnen, hinzufügen von Verschlüsselung und alle, die Spaß Sachen, WCF müsste wissen, wie zu wickeln diesen Strom, um es wiederum in die "echte" Nachricht, die ich glaube nicht, dass es funktioniert.Jedoch die I-need-to-return-a-stream-aber-Komponenten-X-will-zu-schreiben-zu-eins-Szenario ist die häufigste, und ich habe eine catch-all-Lösung, die ich für dieses Szenario zu schaffen, eine zwei-Wege-Strom und erzeugen Sie einen worker-thread zu schreiben. Die einfachste und sicherste Weg, dies zu tun (und damit meine ich, die Art und Weise beinhaltet, dass das schreiben des least-code und daher am wenigsten buggy) ist die Verwendung von anonymen pipes.
Hier ist ein Beispiel für eine Methode, die zurückgibt einen
AnonymousPipeClientStream
, die verwendet werden können in WCF-Nachrichten, MVC Ergebnisse, und so weiter - wo immer Sie wollen, zum umkehren der Richtung:Beispiel dafür wäre:
Nur zwei Vorbehalte zu diesem Ansatz:
Wird es scheitern, wenn die
writeAction
alles tut, um über den Bach (das ist der Grund, warum die test-Methode nicht wirklich entsorgtStreamWriter
- denn das würde über den zugrunde liegenden stream);Könnte es scheitern, wenn die
writeAction
eigentlich nicht schreiben, keine Daten, daWaitForPipeDrain
sofort zurück und erstellen Sie eine race-Bedingung. (Wenn dies ist ein Anliegen, können Sie code, die ein wenig mehr defensiv um dies zu vermeiden, aber es erschwert die Sache noch viel für einen seltenen Grenzfall.)Hoffentlich, die hilft, in Ihrem speziellen Fall.
MemoryStream
für Ihre Komponente zu schreiben und dann wieder das.PipeStream
Klassen alle steigen ausSystem.IO.Stream
.GetPipedStream()
Umsetzung. Lange Geschichte kurz:new AnonymousPipeClientStream(pipeServer.GetClientHandleAsString())
wird, erstellen Sie eine zweiteSafeHandle
bezieht sich auf die gleiche handle-Wert, was potenziell zu einer völlig anderen Griff befreit zu werden, wenn der GC abholen, dassSafeHandle
(das gleiche handle-Wert haben kann, wurde wieder an diesem Punkt, weil die erstenSafeHandle
bereits veröffentlicht). Fix: verwenden Sienew AnonymousPipeClientStream(PipeDirection.In, pipeServer.ClientSafePipeHandle)
statt. Ich werde Bearbeiten Sie die Antwort.QueueUserWorkItem
der Prozess wird beendet. Dies ist wahrscheinlich, da die Leitung wird unterbrochen, wenn der client die Verbindung trennt, während Sie noch schreiben, die Antwort.WCF streaming funktioniert in beide Richtungen - Ihre Kunden hochladen können, Zeug in einem Bach, aber Ihre WCF-service kann auch senden Zeug in einem Bach. Sie kann definitiv schreiben Sie einen Dienst, dass die streams wieder große Dateien anhand Ihrer Datei namens oder einer ID oder so - absolut.
Wenn Sie möchten, senden die Daten zurück aus dem service, die Sie brauchen, dies zu tun in der Rückgabewert von Ihrem service-Methode, die muss der Typ
Stream
- Sie kann nicht (soweit ich weiß) "Angebot" einen stream zum schreiben in die WCF-Dienst erstellen einer Antwort-Datenstrom aus und senden Sie es zurück.Haben Sie ausgecheckt haben, MSDN Streaming Message Transfer oder David Wood blog-post oder Kjell-Sverre blog-post auf WCF streaming? Sie sind alle sehr schön zeigen, welche config-Einstellungen, die Sie benötigen (im Grunde die Einstellung der
TransferMode
in Ihrer Bindung configStreamed
,StreamedRequest
oderStreamedResponse
).