您的位置:首页 > 其它

WCF 传送二进制流数据 stream

2014-09-03 20:47 162 查看
WCF 支持传送二进制流数据,但有一定的限制。

只有 BasicHttpBinding、WebHttpBinding、NetTcpBinding 和 NetNamedPipeBinding 支持传送流数据。

流数据类型必须是可序列化的 Stream 或 MemoryStream。

传递时消息体(Message Body)中不能包含其他数据。

我们先看看下面的例子。

注意将 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)中不能包含其他数据" 是什么意思?我们修改一下上面的契约,除了传递文件流外,我们还希望传递文件名。

[ServiceContract]

public interface IFileService

{

[OperationContract]

void Upload(string filename, Stream stream);

}

// ... 其他代码暂略 ...

当你修改完代码后,运行时你发现触发了一个 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 肯定不行。 没错!你应该记得 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();

}

}

}

问题解决了。上面的例子使用 BaseHttpBinding,如果使用 NetTcpBinding,相信速度要快很多。除了向服务器传送流外,也可反向返回流数据。

[ServiceContract]

public interface IFileService

{

[OperationContract]

void Upload(Stream stream);

[OperationContract]

Stream Download(string filename);

}

虽然服务器在操作结束时会自动关闭客户端 Request Stream,但个人建议还是使用 try...finnaly... 自主关闭要好一些,因为意外总是会发生的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: