轉:WCF傳送二進制流數據基本實現步驟詳解

來自:http://developer.51cto.com/art/201002/185444.htm服務器

WCF傳送二進制流數據基本實現步驟詳解

2010-02-26 16:10 佚名 CSDN  

WCF傳送二進制流數據的相關操做方法在實際應用中是一個比較基礎的操做應用。咱們在這裏將會針對此作一個詳細介紹。ui

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

相關文章
相關標籤/搜索