WCF和流请求和响应

时间:2010-04-28 02:49:02

标签: .net wcf streaming

在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)
    }
}

客户端代码是这样的:

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

(取自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); 
    }
}

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

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

感谢。

2 个答案:

答案 0 :(得分: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);
}

这个例子的用法是:

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);
        }
    });
}

关于这种方法的两个警告:

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

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

  3. 希望这对您的具体情况有所帮助。

答案 1 :(得分:2)

WCF流可以双向工作 - 您的客户端可以在流中上传内容,但您的WCF服务也可以在流中发送内容。您绝对可以编写一个服务,根据文件名或某些ID或其他内容回送大型文件 - 绝对是。

如果您想从服务中发回数据,您需要在服务方法的返回值中执行此操作,该方法需要为Stream类型 - 您不能(据我所知)“提供“要写入的流 - WCF服务将创建响应流并将其发回。

您是否在WCF流媒体上查看了MSDN Streaming Message TransferDavid Wood's blog postKjell-Sverre's blog post?它们都能很好地显示您需要的配置设置(基本上将绑定配置中的TransferMode设置为StreamedStreamedRequestStreamedResponse