在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中,如果是这样,怎么样?绑定,界面等所需的配置设置是什么?什么是术语?
也许它会起作用? (我还没试过)
感谢。
答案 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);
}
});
}
关于这种方法的两个警告:
如果writeAction
做任何事情来处理流(这就是为什么测试方法实际上没有处理StreamWriter
- 因为那将处理基础流),它将失败; < / p>
如果writeAction
实际上没有写任何数据,它可能会失败,因为WaitForPipeDrain
将立即返回并创建竞争条件。 (如果这是一个问题,你可以采取更多的防御措施来避免这种情况,但是对于罕见的边缘情况,它会使事情复杂化。)
希望这对您的具体情况有所帮助。
答案 1 :(得分:2)
WCF流可以双向工作 - 您的客户端可以在流中上传内容,但您的WCF服务也可以在流中发送内容。您绝对可以编写一个服务,根据文件名或某些ID或其他内容回送大型文件 - 绝对是。
如果您想从服务中发回数据,您需要在服务方法的返回值中执行此操作,该方法需要为Stream
类型 - 您不能(据我所知)“提供“要写入的流 - WCF服务将创建响应流并将其发回。
您是否在WCF流媒体上查看了MSDN Streaming Message Transfer或David Wood's blog post或Kjell-Sverre's blog post?它们都能很好地显示您需要的配置设置(基本上将绑定配置中的TransferMode
设置为Streamed
,StreamedRequest
或StreamedResponse
。