一个流中的多个流将无法正确传递给客户端
Multiple stream in one stream will not passed to client properly
在 WCF 服务中,我根据 填充 Stream,例如:
result.Stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(result.Stream);
foreach (string fileN in zipFiles)
{
byte[] fileBytes = File.ReadAllBytes(fileN);
writer.Write(BitConverter.GetBytes(fileBytes.Length), 0, 4);
writer.Write(fileBytes, 0, fileBytes.Length);
}
writer.Flush();
return result;
在此之前,我return通过这个流式传输并且一切都在服务端和客户端工作:
result.Stream = new MemoryStream(File.ReadAllBytes(fileN));
流成为 MessageBodyMember
但 nut 现在将其更改为将所有文件保存在一个流中。
客户端测试方法:
ExportClient export = new ExportClient("exportEndPoint");
ExportResult_C result = export.Export(source);
result.Stream.Position = 0;
//result.Stream.SaveToFile("d:\kkk.log");
BinaryReader reader = new BinaryReader(result.Stream, System.Text.Encoding.UTF8);
string pathToSave = string.Empty;
while (result.Stream.Position < result.Stream.Length)
{
int size = reader.ReadInt32();
byte[] data = reader.ReadBytes(size);
pathToSave = "D:\test\" + new Random().Next(0, 2564586).ToString() + ".zip";
File.WriteAllBytes(pathToSave, data);
}
端点地址:
<endpoint address="net.tcp://localhost:2082/Exchange/Export.svc" binding="netTcpBinding" bindingConfiguration="largeSizeStreamTcp"
contract="xxx" name="exportEndPoint"/>
和绑定配置:
<netTcpBinding>
<binding openTimeout="00:00:03" maxReceivedMessageSize="2000000000" transferMode="Streamed" maxBufferSize="2000000000" >
<readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
<security mode="None" />
</binding>
<binding name="largeSizeStreamTcp" transferMode="Streamed" receiveTimeout="00:30:00" sendTimeout="00:30:00" openTimeout="00:00:01" maxReceivedMessageSize="2000000000" maxBufferSize="2000000000" >
<readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
<security mode="None" />
</binding>
</netTcpBinding>
<netNamedPipeBinding>
我相信端点和绑定是正确的,因为我能够 return 一个文件流并将其保存回来,但现在服务端没有问题,但是当它从客户端获取时,Stream 丢失了它的内容、长度、位置。
这真的让我很生气!!!
有谁知道为什么会发生这种情况(在客户端)?
Wooow,我终于成功地正确实施了我们的方案,将答案放在这里也许有人想使用该解决方案在一个流中处理 returns 多个文件。
有几个示例到 return 多个文件,但它们都是 returning 字节数组,我更喜欢 return 流,因为很多原因,重要的是流对于大文件会表现得更好,因为不是所有的文件都需要一次读入内存并且向后兼容我的情况。
所以在第一步我创建了一个可序列化的DataContract
来保存文件名及其内容字节。
[DataContract]
[Serializable]
public class ExportSourceFiles_C
{
[DataMember]
public string Name;
[DataMember]
public byte[] Content;
}
在 第二步 将创建 ExportSourceFile_C
的列表,如下所示:
List<ExportSourceFiles_C> sourceFiles = new List<ExportSourceFiles_C>();
string[] zipFiles = Directory.GetFiles(zipRoot);
foreach (string path in zipFiles)
{
byte[] fileBytes = File.ReadAllBytes(path);
sourceFiles.Add(new ExportSourceFiles_C()
{
Name = Path.GetFileName(path),
Content = fileBytes
});
}
在第三步,提到的列表应该序列化为result.Stream
,如:
result.Stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(result.Stream, sourceFiles);
result.Stream.Position = 0;
return result;
在客户端,这足以将流反序列化为 ExportSourceFiles_C
的列表,因此客户端的最后一步应该是这样的:
ExportClient export = new ExportClient("exportEndPoint");
ExportResult_C result = export.Export(source);
BinaryFormatter formatter = new BinaryFormatter();
List<ExportSourceFiles_C> deserialisedFiles = (List<ExportSourceFiles_C>)formatter.Deserialize(result.Stream);
foreach (ExportSourceFiles_C file in deserialisedFiles)
File.WriteAllBytes("d:\" + file.Name, file.Content);
一切正常,没有任何问题。
尽情享受吧。
在 WCF 服务中,我根据
result.Stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(result.Stream);
foreach (string fileN in zipFiles)
{
byte[] fileBytes = File.ReadAllBytes(fileN);
writer.Write(BitConverter.GetBytes(fileBytes.Length), 0, 4);
writer.Write(fileBytes, 0, fileBytes.Length);
}
writer.Flush();
return result;
在此之前,我return通过这个流式传输并且一切都在服务端和客户端工作:
result.Stream = new MemoryStream(File.ReadAllBytes(fileN));
流成为 MessageBodyMember
但 nut 现在将其更改为将所有文件保存在一个流中。
客户端测试方法:
ExportClient export = new ExportClient("exportEndPoint");
ExportResult_C result = export.Export(source);
result.Stream.Position = 0;
//result.Stream.SaveToFile("d:\kkk.log");
BinaryReader reader = new BinaryReader(result.Stream, System.Text.Encoding.UTF8);
string pathToSave = string.Empty;
while (result.Stream.Position < result.Stream.Length)
{
int size = reader.ReadInt32();
byte[] data = reader.ReadBytes(size);
pathToSave = "D:\test\" + new Random().Next(0, 2564586).ToString() + ".zip";
File.WriteAllBytes(pathToSave, data);
}
端点地址:
<endpoint address="net.tcp://localhost:2082/Exchange/Export.svc" binding="netTcpBinding" bindingConfiguration="largeSizeStreamTcp"
contract="xxx" name="exportEndPoint"/>
和绑定配置:
<netTcpBinding>
<binding openTimeout="00:00:03" maxReceivedMessageSize="2000000000" transferMode="Streamed" maxBufferSize="2000000000" >
<readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
<security mode="None" />
</binding>
<binding name="largeSizeStreamTcp" transferMode="Streamed" receiveTimeout="00:30:00" sendTimeout="00:30:00" openTimeout="00:00:01" maxReceivedMessageSize="2000000000" maxBufferSize="2000000000" >
<readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
<security mode="None" />
</binding>
</netTcpBinding>
<netNamedPipeBinding>
我相信端点和绑定是正确的,因为我能够 return 一个文件流并将其保存回来,但现在服务端没有问题,但是当它从客户端获取时,Stream 丢失了它的内容、长度、位置。
这真的让我很生气!!!
有谁知道为什么会发生这种情况(在客户端)?
Wooow,我终于成功地正确实施了我们的方案,将答案放在这里也许有人想使用该解决方案在一个流中处理 returns 多个文件。
有几个示例到 return 多个文件,但它们都是 returning 字节数组,我更喜欢 return 流,因为很多原因,重要的是流对于大文件会表现得更好,因为不是所有的文件都需要一次读入内存并且向后兼容我的情况。
所以在第一步我创建了一个可序列化的DataContract
来保存文件名及其内容字节。
[DataContract]
[Serializable]
public class ExportSourceFiles_C
{
[DataMember]
public string Name;
[DataMember]
public byte[] Content;
}
在 第二步 将创建 ExportSourceFile_C
的列表,如下所示:
List<ExportSourceFiles_C> sourceFiles = new List<ExportSourceFiles_C>();
string[] zipFiles = Directory.GetFiles(zipRoot);
foreach (string path in zipFiles)
{
byte[] fileBytes = File.ReadAllBytes(path);
sourceFiles.Add(new ExportSourceFiles_C()
{
Name = Path.GetFileName(path),
Content = fileBytes
});
}
在第三步,提到的列表应该序列化为result.Stream
,如:
result.Stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(result.Stream, sourceFiles);
result.Stream.Position = 0;
return result;
在客户端,这足以将流反序列化为 ExportSourceFiles_C
的列表,因此客户端的最后一步应该是这样的:
ExportClient export = new ExportClient("exportEndPoint");
ExportResult_C result = export.Export(source);
BinaryFormatter formatter = new BinaryFormatter();
List<ExportSourceFiles_C> deserialisedFiles = (List<ExportSourceFiles_C>)formatter.Deserialize(result.Stream);
foreach (ExportSourceFiles_C file in deserialisedFiles)
File.WriteAllBytes("d:\" + file.Name, file.Content);
一切正常,没有任何问题。
尽情享受吧。