我有什么?
我有一个接受Stream对象的WCF合约。
我需要什么?
我想将合同转换为接受多个流。但是,在WCF中传递多个流存在一些问题。现在我有两个选择,
(1)多次调用WCF方法
(2)更改合同以接受包含所有文件内容的二维字节数组
有人可以告诉我哪个选项更好吗?
提前致谢!
答案 0 :(得分:8)
我们通过在客户端上构建一个Stream包装器实现来解决这个问题,该实现将端口列表连接在一起,端到端(例如,.Read委托给第一个流 - 当它在流1上遇到EOF时,它开始读取流2,等等)。它有一个元数据属性,它包含流的名称和它们的位置,我们在[MessageHeader]属性arg中调用它,它表示流中的内容和每个流的偏移量(客户端流必须支持.Length)。服务器上的流的消费者知道如何读取该元数据对象并按顺序分发流列表。唯一的限制是它们必须按顺序处理。效果很棒!
答案 1 :(得分:4)
在WCF中,不能在单个服务方法中拥有多个流参数。这只是一个系统限制。
请参阅MSDN documentation on WCF streaming:
对流转移的限制
使用流式传输模式 导致运行时间强制执行 其他限制。
跨越的发生的操作 流式运输可以签订合同 最多一个输入或输出 参数。该参数对应 对整个信息和 必须是Message,派生类型 流,或IXmlSerializable 实现。有返回值 对于一个操作相当于 有一个输出参数。
所以现在,你所能做的就是多次调用你的方法。
马克
答案 2 :(得分:1)
在我的系统中,我需要向WCF服务发送一个FileStream和一个自定义数据列表。这就是我如何将它们组合成一个流并将其发送到服务,该服务将结果流返回给客户端:
服务合同:
[ServiceContract]
[XmlSerializerFormat]
public interface IMyService
{
[OperationContract]
ResultClass MyOperation(Parameters param);
}
返回流:
[MessageContract]
public class ResultClass
{
[MessageBodyMember]
public System.IO.Stream Stream { get; set; }
}
输入流:
[MessageContract]
public class Parameters
{
[MessageHeader]
public long Length1 { get; set;}
[MessageHeader]
public long Length12 { get; set;}
[MessageBodyMember]
public Stream Stream { get; set;}
}
在WCF客户端:
public static void BuildStream(string filePath, List<CustomData> otherParams, ref Parameters param)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
MemoryStream allStreams = new MemoryStream();
MemoryStream dataStream = new MemoryStream();
formatter.Serialize(dataStream, otherParams);
dataStream.Seek(0, SeekOrigin.Begin);
fs.Seek(0, SeekOrigin.Begin);
fs.CopyTo(allStreams);
dataStream.CopyTo(allStreams);
param.TemplateLength = fs.Length;
param.DataLength = dataStream.Length;
param.Stream = allStreams;
param.Stream.Seek(0, SeekOrigin.Begin);
}
在服务实现中,从组合流中提取第一个和第二个流:
List<CustomData> dataSheets;
using (MemoryStream ms = new MemoryStream())
{
MemoryStream dataStream;
BinaryFormatter formatter = new BinaryFormatter();
byte[] templatebuffer, databuffer;
filebuffer = new byte[m_param.Length1];
databuffer = new byte[m_param.Length2];
// Get the whole stream
m_param.Stream.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
// Get the first stream
ms.Read(templatebuffer, 0, (int)m_param.TemplateLength);
// Get the custom data
ms.Read(databuffer, 0, (int)m_param.DataLength);
using (dataStream = new MemoryStream(databuffer))
{
dataStream.Seek(0, SeekOrigin.Begin);
dataSheets = (List<DataSheet>) formatter.Deserialize(dataStream);
m_param.Stream.Close();
...
答案 3 :(得分:0)