WCF传送二进制流数据基本实现步骤详解

引用:http://www.cnblogs.com/lusunqing/p/3399594.html

WCF传送二进制流数据的相关操作方法在实际应用中是一个比较基础的操作应用。我们在这里将会针对此做一个详细介绍。

我们知道,在实现WCF传送二进制流数据这一操作过程中,会有一些限制因素。我们在实际应用中要特别注意这一点。今天我们就会针对这方面的问题做一个详细的介绍,希望对大家有所帮助。

只有 BasicHttpBinding、WebHttpBinding、NetTcpBinding 和 NetNamedPipeBinding 支持传送流数据。
    流数据类型必须是可序列化的 Stream 或 MemoryStream。
    传递时消息体(Message Body)中不能包含其他数据。

我们先看看下面的WCF传送二进制流数据例子。

注意将 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);
    }
    // ... 其他代码暂略 ...

当你修改完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"

那么该怎么办呢?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... 自主关闭要好一些,因为意外总是会发生的。

WCF传送二进制流数据的全部操作方法就为大家介绍到这里。

时间: 2024-11-02 09:45:49

WCF传送二进制流数据基本实现步骤详解的相关文章

保存二进制流数据到文件

/// <summary>         /// 保存二进制流文件 /// </summary> /// <param name="files">文件流数据</param> /// <param name="systemCode">系统编号</param> /// <param name="moduleName">模块名称</param> /// &

Jmeter入门13 jmeter发送application/octet-stream二进制流数据

http接口请求header里面 content-type: application/octet-stream  (二进制流数据),如何用jmeter发送请求? 1 添加http请求头 2 http请求 files upload里面写上文件的绝对地址 发送的文件内容:1 由开发提供的文件  2 有的是通过fiddler抓包获取的二进制流拷贝到文件里保存 the end! 原文地址:https://www.cnblogs.com/dinghanhua/p/9822734.html

ORACLE EXPDP IMPDP数据导入导出命令详解及同EXP IMP命令详细对比

ORACLE EXPDP IMPDP数据导入导出命令详解及同EXP IMP 命令详细对比 一.EXPDP IMPDP EXP IMP 可以实现 1.可以实现逻辑备份和逻辑恢复 2.可以在数据库用户之间移动对象 3.可以在数据库之间移动对象 4.可以实现表空间转移 二.EXPDP的命令详解 C:\Users\Administrator>20:42:32.90>expdp help=y Export: Release 11.2.0.1.0 - Production on 星期六 10月 10 09

linux Mysql 主从复制 原理介绍和步骤详解

大家好,我是霸王卸甲,今天我给大家带来的是linux数据库中的主从复制的简单介绍和步骤详解. 主从复制 mysql主从复制 灵活 一主一从 主主复制 一主多从---扩展系统读取的性能,因为读是在从库读取的: 多主一从---5.7开始支持 联级复制--- 用途及条件 mysql主从复制用途 实时灾备,用于故障切换 读写分离,提供查询服务 备份,避免影响业务 主从部署必要条件: 主库开启binlog日志(设置log-bin参数) 主从server-id不同 从库服务器能连通主库 主从原理mysql主

安装MACOS操作步骤详解

安装MACOS操作步骤详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于安装MAC的操作系统其实大家都知道可以让客服帮忙提供软件上的支持,而且苹果客服都很有礼貌呢,而且非常的有耐心.特别感谢她们的帮助,让我对MAC的操作系统的好感度有了大大的提升.起初,我刚刚拿到我的本的时候是去年,因为我压根并不看好笔记本,我到现在也非常喜欢台式机,因为体验度是相当棒的,但是由于工作的原因,可能是要去出差的时候带着个台式机到处跑也不太合适,于是就决定买一个低配的笔记本.刚刚拿到笔记本第

gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解

摘自http://blog.csdn.net/elfprincexu/article/details/45043971 gcc/g++等编译器 编译原理: 预处理,编译,汇编,链接各步骤详解 C和C++编译器是集成的,编译一般分为四个步骤: 预处理(preprocessing)  ----------------- cpp/ gcc -E  编译(compilation) ------------------ cc1 / gcc -S 汇编(assembly)  ----------------

Oracle 10g创建表空间的完整步骤详解

本文我们主要介绍了Oracle 10g创建表空间的完整步骤,包括表空间的创建与删除.为应用创建用户以及权限的授予等操作,希望能够对您有所帮助. AD:WOT2014:用户标签系统与用户数据化运营培训专场 Oracle 10g数据库中,当在数据库中创建用户时,基于应用性能和管理方面的考虑,最好为不同的用户创建独立的表空间. 那么创建表空间的步骤是怎样实现的呢?本文我们主要就介绍了这一部分内容,接下来就让我们一起来了解一下这部分内容吧. 1.创建表空间 不论是Lnux环境,还是Wndows环境,都要

解析activity之间数据传递方法的详解

转自:http://www.jb51.net/article/37227.htm 本篇文章是对activity之间数据传递的方法进行了详细的分析介绍,需要的朋友参考下 1  基于消息的通信机制 Intent--------boudle,extra用这种简单的形式,一般而言传递一些简单的类型是比较容易的,如int.string等详细介绍下Intent机制Intent包含两部分:1 目的[action]-------要去到哪里去2 内容[category.data]----------路上带些什么,

(转)MVC 3 数据验证 Model Validation 详解

继续我们前面所说的知识点进行下一个知识点的分析,这一次我们来说明一下数据验证.其实这是个很容易理解并掌握的地方,但是这会浪费大家狠多的时间,所以我来总结整理一下,节约一下大家宝贵的时间. 在MVC 3中 数据验证,已经应用的非常普遍,我们在web form时代需要在View端通过js来验证每个需要验证的控件值,并且这种验证的可用性很低.但是来到了MVC 新时代,我们可以通过MVC提供的数据验证Attribute来进行我们的数据验证.并且MVC 提供了客户端和服务器端 双层的验证,只有我们禁用了客