咱們知道,在實現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傳送二進制流數據的所有操做方法就爲你們介紹到這裏。