Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
450 views
in Technique[技术] by (71.8m points)

c# - Multiple stream in one stream will not passed to client properly

In WCF service I fill Stream according to this question like :

   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; 

before this I was returning stream by this and everything works in service and client side:

 result.Stream = new MemoryStream(File.ReadAllBytes(fileN));

Stream be MessageBodyMember but nut now changed it to save all file in one stream.

and Test method in client side:

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

the endpoint address:

 <endpoint address="net.tcp://localhost:2082/Exchange/Export.svc" binding="netTcpBinding" bindingConfiguration="largeSizeStreamTcp"
    contract="xxx" name="exportEndPoint"/>

and binding configuration:

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

I believe endpoint and binding is correct as I was able to return one file stream and save it back but now there is no prob in service side but when it will get from client side, Stream got lost it's content,length,position.

this is really drive me up the wall!!!

does anyone know why this is occurred(in client side) ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Wooow, Finally I get success to implement our scenario properly, going to put the answer here maybe someone wants to use the solution to returns multiple files in one stream.

there are several sample to return multiple files but all of them are returning byte array, I prefer to return stream because of many reason, the important thing is streams will perform better for large files since not all of it needs to be read into memory at one time and backward compatibility for my case.

So at the first step I have created a serializable DataContract to hold the name of file and it's content byte.

[DataContract]
[Serializable]
public class ExportSourceFiles_C
{
    [DataMember]
    public string Name;
    [DataMember]
    public byte[] Content;
}

at the second step a list of ExportSourceFile_C will be created like:

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

at the third step the mentioned list should be serialized to result.Stream like:

  result.Stream = new MemoryStream();
  BinaryFormatter formatter = new BinaryFormatter();
  formatter.Serialize(result.Stream, sourceFiles);
  result.Stream.Position = 0;
  return result;

in client side this is enough deserialize the stream to list of ExportSourceFiles_C so the last step in client side should be something like this:

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

everything works like a charm without any problem.

enjoy.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...