WCF和流请求和响应

Che*_*eso 13 .net streaming wcf

在WCF中,我不能将服务写入客户端接收的流吗?

WCF支持流请求,响应或两者.我想支持一种情况,即数据生成器(流式传输请求时的客户端或流式响应时的服务器)可以在流上写入.这支持吗?

类比是来自ASP.NET请求的Response.OutputStream.在ASPNET中,任何页面都可以在输出流上调用Write,并且客户端会接收内容.我可以在WCF服务中执行类似的操作 - 在客户端接收的流上调用Write吗?

让我用WCF插图解释一下.WCF中最简单的Streaming示例是将FileStream返回给客户端的服务.这是一个流式响应.实现此目的的服务器代码如下:

[ServiceContract]
public interface IStreamService
{
    [OperationContract]
    Stream GetData(string fileName);
}
public class StreamService : IStreamService
{
    public Stream GetData(string filename)
    {
        return new FileStream(filename, FileMode.Open)
    }
}
Run Code Online (Sandbox Code Playgroud)

客户端代码是这样的:

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);
Run Code Online (Sandbox Code Playgroud)

(例子来自http://blog.joachim.at/?p=33)

清楚吧?服务器将Stream返回给客户端,客户端调用Read.

客户端是否可以提供Stream,并且服务器可以在其上调用Write?
换句话说,不是拉模型 - 客户端从服务器提取数据 - 它是推模型,客户端提供"接收"流并且服务器写入其中.服务器端代码可能类似于:

[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); 
    }
}
Run Code Online (Sandbox Code Playgroud)

这可能在WCF中,如果是这样,怎么样?绑定,界面等所需的配置设置是什么?什么是术语?

也许它会起作用?(我还没试过)

谢谢.

Aar*_*ght 9

相当肯定,有没有WCF绑定,这将让你的组合字面上写到客户端的数据流.这应该是合乎逻辑的,因为在表面之下的某个地方肯定会有一个NetworkStream,但是一旦你开始添加加密和所有有趣的东西,WCF将不得不知道如何包装这个流将它变成"真实的"消息,我不认为它.

但是,I-need-to-return-a-stream-but-component-X-want-to-write-to-one场景是一个常见的场景,我有一个全能解决方案,我用于这个场景,这是创建一个双向流并产生一个工作线程来写入它.在最简单最安全的方式做到这一点(我的意思是,这涉及编写最少的代码,因此最有可能是越野车的方式)是使用匿名管道.

这是一个返回AnonymousPipeClientStream可以在WCF消息,MVC结果等中使用的方法的示例- 您想要反转方向的任何地方:

static Stream GetPipedStream(Action<Stream> writeAction)
{
    AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream();
    ThreadPool.QueueUserWorkItem(s =>
    {
        using (pipeServer)
        {
            writeAction(pipeServer);
            pipeServer.WaitForPipeDrain();
        }
    });
    return new AnonymousPipeClientStream(PipeDirection.In, pipeServer.ClientSafePipeHandle);
}
Run Code Online (Sandbox Code Playgroud)

一个示例用法是:

static Stream GetTestStream()
{
    string data = "The quick brown fox jumps over the lazy dog.";
    return GetPipedStream(s =>
    {
        StreamWriter writer = new StreamWriter(s);
        writer.AutoFlush = true;
        for (int i = 0; i < 50; i++)
        {
            Thread.Sleep(50);
            writer.WriteLine(data);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

关于这种方法只有两点需要注意:

  1. 如果writeAction做任何事情来处理流,它将失败(这就是为什么测试方法实际上没有处理StreamWriter- 因为那会处置底层流);

  2. 如果writeAction实际上没有写入任何数据,它可能会失败,因为它WaitForPipeDrain会立即返回并创建竞争条件.(如果这是一个问题,你可以采取更多的防御措施来避免这种情况,但是对于罕见的边缘情况,它会使事情复杂化.)

希望这有助于您的具体情况.