WCF傳送二進(jìn)制流數(shù)據(jù)基本實(shí)現(xiàn)步驟詳解
我們知道,在實(shí)現(xiàn)WCF傳送二進(jìn)制流數(shù)據(jù)這一操作過(guò)程中,會(huì)有一些限制因素。我們?cè)趯?shí)際應(yīng)用中要特別注意這一點(diǎn)。今天我們就會(huì)針對(duì)這方面的問(wèn)題做一個(gè)詳細(xì)的介紹,希望對(duì)大家有所幫助。#t#
只有 BasicHttpBinding、WebHttpBinding、NetTcpBinding 和 NetNamedPipeBinding 支持傳送流數(shù)據(jù)。
流數(shù)據(jù)類(lèi)型必須是可序列化的 Stream 或 MemoryStream。
傳遞時(shí)消息體(Message Body)中不能包含其他數(shù)據(jù)。
我們先看看下面的WCF傳送二進(jìn)制流數(shù)據(jù)例子。
注意將 Binding.TransferMode 設(shè)置為 TransferMode.Streamed,我們還可以修改 Binding.MaxReceivedMessageSize 來(lái)調(diào)整消息大小(默認(rèn)是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();
- }
- }
- }
一切正常。那么 "傳遞時(shí)消息體(Memory Body)中不能包含其他數(shù)據(jù)" 是什么意思?我們修改一下上面的契約,除了傳遞文件流外,我們還希望傳遞文件名。
- [ServiceContract]
- public interface IFileService
- {
- [OperationContract]
- void Upload(string filename, Stream stream);
- }
- // ... 其他代碼暫略 ...
當(dāng)你修改完WCF傳送二進(jìn)制流數(shù)據(jù)的代碼后,運(yùn)行時(shí)你發(fā)現(xiàn)觸發(fā)了一個(gè) 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"
那么該怎么辦呢?DataContract 肯定不行。 沒(méi)錯(cuò)!你應(yīng)該記得 MessageContract,將 filename 放到 MessageHeader 里面就行了。
- [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();
- }
- }
- }
問(wèn)題解決了。上面的例子使用 BaseHttpBinding,如果使用 NetTcpBinding,相信速度要快很多。除了向服務(wù)器傳送流外,也可反向返回流數(shù)據(jù)。
- [ServiceContract]
- public interface IFileService
- {
- [OperationContract]
- void Upload(Stream stream);
- [OperationContract]
- Stream Download(string filename);
- }
雖然服務(wù)器在操作結(jié)束時(shí)會(huì)自動(dòng)關(guān)閉客戶端 Request Stream,但個(gè)人建議還是使用 try...finnaly... 自主關(guān)閉要好一些,因?yàn)橐馔饪偸菚?huì)發(fā)生的。
WCF傳送二進(jìn)制流數(shù)據(jù)的全部操作方法就為大家介紹到這里。