zoukankan      html  css  js  c++  java
  • 转:WCF传送二进制流数据基本实现步骤详解

    来自:http://developer.51cto.com/art/201002/185444.htm

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

    2010-02-26 16:10 佚名 CSDN  

    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传送二进制流数据的全部操作方法就为大家介绍到这里。

  • 相关阅读:
    6.66 分钟,一文Python爬虫解疑大全教入门!
    十分钟快速入门 Python,看完即会,不用收藏!
    Python3中真真假假True、False、None等含义详解
    Python基础系列讲解——时间模块详解大全之time模块
    超详细Pycharm部署项目视频教程
    Python进阶量化交易专栏场外篇7- 装饰器计算代码时间
    docker 基本命令
    Linux常用命令
    Docker-部署Mysql
    docker 容器内运行vim命令
  • 原文地址:https://www.cnblogs.com/lusunqing/p/3399594.html
Copyright © 2011-2022 走看看