咱们知道,在实现WCF传送二进制流数据这一操做过程当中,会有一些限制因素。咱们在实际应用中要特别注意这一点。今天咱们就会针对这方面的问题作一个详细的介绍,但愿对你们有所帮助。spa
只有 BasicHttpBinding、WebHttpBinding、NetTcpBinding 和 NetNamedPipeBinding 支持传送流数据。
流数据类型必须是可序列化的 Stream 或 MemoryStream。
传递时消息体(Message Body)中不能包含其余数据。code
咱们先看看下面的WCF传送二进制流数据例子。htm
注意将 Binding.TransferMode 设置为 TransferMode.Streamed,咱们还能够修改 Binding.MaxReceivedMessageSize 来调整消息大小(默认是64KB)。对象
[ServiceContract] public interface IFileService { [OperationContract] void Upload(Stream stream); } public class FileService : IFileService, IDisposable { public void Upload(Stream stream) { FileStream file = new FileStream("test.dll", FileMode.Create); try { BinaryWriter writer = new BinaryWriter(file); BinaryReader reader = new BinaryReader(stream); byte[] buffer; do { buffer = reader.ReadBytes(1024); writer.Write(buffer); } while (buffer.Length > 0); } finally { file.Close(); stream.Close(); } } public void Dispose() { Console.WriteLine("Dispose..."); } } public class WcfTest { public static void Test() { AppDomain.CreateDomain("Server").DoCallBack(delegate { ServiceHost host = new ServiceHost(typeof(FileService), new Uri("http://localhost:8080/FileService")); BasicHttpBinding binding = new BasicHttpBinding(); binding.TransferMode = TransferMode.Streamed; host.AddServiceEndpoint(typeof(IFileService), binding, ""); host.Open(); }); BasicHttpBinding binding2 = new BasicHttpBinding(); binding2.TransferMode = TransferMode.Streamed; IFileService channel = ChannelFactory<IFileService>.CreateChannel(binding2, new EndpointAddress("http://localhost:8080/FileService")); using (channel as IDisposable) { FileStream stream = new FileStream("MyLibrary2.dll", FileMode.Open); channel.Test(stream); stream.Close(); } } }
一切正常。那么 "传递时消息体(Memory Body)中不能包含其余数据" 是什么意思?咱们修改一下上面的契约,除了传递文件流外,咱们还但愿传递文件名。blog
[ServiceContract] public interface IFileService { [OperationContract] void Upload(string filename, Stream stream); } // ... 其余代码暂略 ...
当你修改完WCF传送二进制流数据的代码后,运行时你发现触发了一个 InvalidOperationException 异常。事务
未处理 System.InvalidOperationException
Message="For request in operation Upload to be a stream the operation must have a single parameter whose type is Stream."
Source="System.ServiceModel"ip
那么该怎么办呢?DataContract 确定不行。 没错!你应该记得 MessageContract,将 filename 放到 MessageHeader 里面就好了。get
[MessageContract] public class FileData { [MessageHeader] public string filename; [MessageBodyMember] public Stream data; } [ServiceContract] public interface IFileService { [OperationContract] void Upload(FileData file); } public class FileService : IFileService, IDisposable { public void Upload(FileData file) { FileStream f = new FileStream(file.filename, FileMode.Create); try { BinaryWriter writer = new BinaryWriter(f); BinaryReader reader = new BinaryReader(file.data); byte[] buffer; do { buffer = reader.ReadBytes(1024); writer.Write(buffer); } while (buffer.Length > 0); } finally { f.Close(); file.data.Close(); } } public void Dispose() { Console.WriteLine("Dispose..."); } } public class WcfTest { public static void Test() { AppDomain.CreateDomain("Server").DoCallBack(delegate { ServiceHost host = new ServiceHost(typeof(FileService), new Uri("http://localhost:8080/FileService")); BasicHttpBinding binding = new BasicHttpBinding(); binding.TransferMode = TransferMode.Streamed; host.AddServiceEndpoint(typeof(IFileService), binding, ""); host.Open(); }); BasicHttpBinding binding2 = new BasicHttpBinding(); binding2.TransferMode = TransferMode.Streamed; IFileService channel = ChannelFactory<IFileService>.CreateChannel(binding2, new EndpointAddress("http://localhost:8080/FileService")); using (channel as IDisposable) { FileData file = new FileData(); file.filename = "test2.dll"; file.data = new FileStream("MyLibrary2.dll", FileMode.Open); channel.Upload(file); file.data.Close(); } } }
问题解决了。上面的例子使用 BaseHttpBinding,若是使用 NetTcpBinding,相信速度要快不少。除了向服务器传送流外,也可反向返回流数据。
[ServiceContract] public interface IFileService { [OperationContract] void Upload(Stream stream); [OperationContract] Stream Download(string filename); }
虽然服务器在操做结束时会自动关闭客户端 Request Stream,但我的建议仍是使用 try...finnaly... 自主关闭要好一些,由于意外老是会发生的。
WCF传送二进制流数据的所有操做方法就为你们介绍到这里。