按此帖实战:http://www.cnblogs.com/zhijianliutang/archive/2011/11/28/2265989.html 

 

此篇小说首假若:
基于http协议利用于大文件传输中的应用,未来大家先解析下wcf中编码器的概念,编码器完成了类的编码,并肩负将Message内部存款和储蓄器中新闻转变为互联网发送的字节流恐怕字节缓冲区(对于发送方而言)。在接收方,编码会将一多级字节转变为内部存款和储蓄器中的音信

在wcf中有多个编码器

    1、TextMessageEncodingBindingElement

       文本新闻编码器是全数的依照Http的绑定的暗中同意编码器,并且是最关心互操作性的全体的自定义绑定的正确性抉择。即为请求/应答形式,此编码器读取和编码标准为SOAP1.1/SOAP1.2的文件音讯,而不会对二进制数据开始展览别的卓殊处理,假如音讯的MessageVersion设置为None,则SOAP信封包装从出口中总结,唯有正文内容实行种类化。

    2、MtomMessageEncodingBindingElement

     
MTOM音信编码器是也是叁个文本编码器,达成对二进制数据的奇异处理,暗许意况下在别的专业绑定中都不会接纳,也正是说须要大家和好定义(一般定义在wsHttpBinding中),因为它是多个严厉按具体景况举办优化的实用工具,只有当二进制数据的量不超越有个别阀值时,MTOM编码才具有优势,假若新闻包罗的二进制数据超越有个别阀值,则那个数据会外部化音讯信封之后的MIME部分

    3、BinaryMessageEncodingBindingElement

    
二进制音讯编码器是Net*绑定的私下认可编码器,当通讯双方都依据WCF时,此编码器始终是情有可原的取舍。二进制音信编码使用.NET二进制XML格式,该格式是XML音信集(Information
Sets,Infosets)的Microsoft特定二进制表示法,与同一的xml1.0表示法相比较爆发的必要量平常较小,并将二进制数据编码为字节流

种种专业绑定都席卷一个预配置编码器,因而暗许情状下Net*前缀的绑定使用二进制编码(通过包涵BinaryMessageEncodingBindingElement类),而BasicHttpBinding和WSHttpBing类则使用文本新闻编码器(通过TextMessageEncodingBindingElement类)

       通常:

      
(1)文本消息编码是讲求互操作性的轻易通讯路径的极品选项,相当于通用性相比较高

      
(2)二进制新闻编码则是其余随意通讯路径的特级选择。日常,对于当个音信而言,二进制编码生成的音信要小于文本编码,并且在通讯会话时期音信大小会逐步变得更小。于文本编码不一样的是,二进制编码不供给对数码开始展览特别处理(例如,使用Base64),当会字节表示为字节即使数据不能够分段,音讯必须登时的法子传送或然当传输运转时数据为完全就绪,则应考虑启用流情势,而且不得不对大型信息(带文本恐怕二进制)启用流情势不能推行音讯正文的数字签名,因为她们供给全方位音信内容开展哈希算法。采取流格局的状态下,当协会和殡葬新闻头时,内容并未完全就绪,由此不能测算数字签名。加密依靠于数字签名验证是还是不是曾经不易的双重布局数据

       
要是消息在传输进度中丢失,可信赖的对话必须在客户端上缓冲已发送的消息以便能够重复传递,并且在将新闻传递给劳务完毕在此之前必须在服务上保存音信以管教音信顺序。以备在未按梯次接受新闻时能够依照科学的顺寻重新排列新闻

上边我们经过两个上传文件的简要程序达成流文件的上传:

有几点大家要求注意:

      
1、在大家流文件上传的时候,要求定义文件的片段性质,这样大家就要求用消息契约代替数据契约形式

      
② 、流文件上传的时候我们定义方法的时候只可以维持四个参数,即音信契约。

先是步、新建文件新闻契约

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.IO;

namespace streamFileUp
{
    /// <summary>
    /// 消息契约(定义与SOAP消息相对应的强类型)
    /// 因为我们用流传输,所以用消息契约代替传统的数据契约
    /// 
    /// </summary>
    [MessageContract]
    public class FileWrapper
    {
        /// <summary>
        ///SOAP的消息头这里即为标记文件的路径
        /// </summary>
        [MessageHeader]
        public string FilePath;
        /// <summary>
        /// SOAP消息的内容,指定成员序列化正文中的元素
        /// </summary>
        [MessageBodyMember]
        public Stream FileData;
    }
    /// <summary>
    /// 返回结果
    /// </summary>
    [MessageContract]
    public class result
    {
        [MessageBodyMember]
        public bool returnresult;
    }
}

using System;
其次步,定义服务契约

using System;
using System.ServiceModel;

namespace streamFileUp
{
    [ServiceContract]
    public interface IStreamed
    {
        /// <summary>
        /// 上传文件
        /// </summary>
        /// 1、支持数据流传输的绑定有:BasicHttpBding、NetTcpBinding和NetNamedPipeBinding
        /// 2、数据流类型必须是可序列化的sream或MemorySream
        /// 3、传递时消息体(Message Body)中不可能包含其他数据,即参数只能有一个streamFileUp.FileWrapper
        /// <param name="fileWrapper">信息载体</param>
        [OperationContract]
        result UploadFile(FileWrapper fileWrapper);
    }
}

其三步、达成类,注释很全,就不解释了

using System;
using System.Collections.Generic;
using System.IO;
using System.ServiceModel;

namespace streamFileUp
{
    public class Streamed : IStreamed
    {
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileWrapper">streamFileUp.FileWrapper</param>
        public result UploadFile(FileWrapper fileWrapper)
        {
            try
            {
                var sourceSream = fileWrapper.FileData;
                var targetSream = new FileStream(fileWrapper.FilePath,
                    FileMode.Create,
                    FileAccess.Write,
                    FileShare.None);
                var buffer = new byte[4096];
                var count = 0;
                while ((count = sourceSream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    targetSream.Write(buffer, 0, count);
                }
                targetSream.Close();
                sourceSream.Close();
            }
            catch (Exception)
            {
                return new result { returnresult = false };
            }
            return new result { returnresult = true }; 
        }
    }
}

第肆步、大家使用自托管,新建服务Nothing playing

using System;
using System.ServiceModel;

namespace streamFileUp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(Streamed)))
            {
                host.Opened += delegate
                {
                    Console.WriteLine("服务已经启动");
                };
                host.Open();
                foreach (var endpoint in host.Description.Endpoints)
                {
                    Console.WriteLine(endpoint.Address.ToString());
                }
                Console.ReadLine();
            }
        }
    }
}

第4步,那里是我们的配备文件,晒一下,注释很详细,记住是布置流传输

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
  <system.serviceModel>
    <services>
      <!--name 提供服务的类名-->
      <!--behaviorConfiguraron 指定相关的行为配置 -->
      <service name="streamFileUp.Streamed"
               behaviorConfiguration="MessageBehavior">
        <!--address - 服务地址-->
        <!--binding - 通信方式-->
        <!--contract - 服务契约-->
        <!--bindingConfiguration - 指定相关的绑定配置-->
        <endpoint
          address="Message/Streamed"
          binding="netTcpBinding"
          contract="streamFileUp.IStreamed"
          bindingConfiguration="StreamedBindingConfiguration" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:12345/Message/Streamed/"/>
            <add baseAddress="net.tcp://localhost:54321/"/>
          </baseAddresses>
        </host>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="MessageBehavior">
          <!--httpGetEnabled - 使用get方式提供服务-->
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <netTcpBinding>
        <!--transferMode - 指示通道是使用流处理模式还是缓冲模式来传输请求和响应消息-->
        <!--maxReceivedMessageSize - 在采用此绑定配置的通道上可接收的最大消息大小(单位:字节)-->
        <!--receiveTimeout - 在传输引发异常之前可用于完成读取操作的时间间隔-->
        <binding 
          name="StreamedBindingConfiguration" 
          transferMode="Streamed" 
          maxReceivedMessageSize="1073741824" 
          receiveTimeout="00:10:00" />
      </netTcpBinding>
    </bindings>

  </system.serviceModel>


</configuration>

到此我们的服务端已经确立成功了,跑一下试试…

XML 1

能够见到大家了解了多少个服务地点,三个是net.tcp、三个是http…其实那中间http地址是援引服务的营地址,其传递方式照旧运用

tcp形式的,一会大家由此客户端验证来下大家的估算。

下边大家起首新建客户端,来连接该服务:

第贰步、新建类库,引用该服务,那中间有几点注意,在流的传输下大家客户端生成代码的时候服务地点是无法用下面的net.tcp…

咱俩供给引用http:……集散地址变更:

XML 2

其三步、完毕客户端上传文件:

using System;
using System.Collections.Generic;
using System.ServiceModel;


namespace client
{
    class Program
    {
        static void Main(string[] args)
        {
            ///自定义绑定
            string strAddress = "net.tcp://localhost:54321/Message/Streamed";      
            ChannelFactory<ServiceFileUp.IStreamed> factory = new ChannelFactory<ServiceFileUp.IStreamed>("NetTcpBinding_IStreamed", new EndpointAddress(strAddress));
            ServiceFileUp.IStreamed service = factory.CreateChannel();

            string filePath = @"G:\wcf学习测试案例\wcf大型数据传输\1.jpg";
            string newFilePath = @"G:\wcf学习测试案例\wcf大型数据传输\2.jpg";

            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); //定义观察者

            watch.Start();
            ServiceFileUp.result returnResult = service.UploadFile(getSreamFromFile(filePath, newFilePath));
            watch.Stop();

            if (returnResult.returnresult)
            {
                Console.WriteLine("上传成功,上传时间为:" + watch.ElapsedMilliseconds);
                Console.ReadLine();
            }
            else
            {
                Console.WriteLine("上传失败");
                Console.ReadLine();
            }
        }
        /// <summary>
        /// 流数据上传文件
        /// </summary>
        /// <param name="file">源文件地址</param>

        public static ServiceFileUp.FileWrapper getSreamFromFile(string file, string newFilePath)
        {
            ServiceFileUp.FileWrapper myFileFw = null;
            try
            {
                var sr = new System.IO.FileStream(
                    file, System.IO.FileMode.Open);
                ServiceFileUp.FileWrapper oneFW = new ServiceFileUp.FileWrapper()
                {
                    FilePath = newFilePath,
                    FileData = sr
                };
                myFileFw = oneFW;
                Console.WriteLine("文件大小为:"+sr.Length.ToString());
                //sr.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            return myFileFw;
        }

    }
}

大家在G盘下边放了1个jpg文件,然后经过上传同样的在该目录下存入大家刚刚上传的公文,那里大家顺便监听了一下上传该文件供给的大运

上面晒一下结实:

XML 3

XML 4

证实文件上传是打响的,上面大家转移一种艺术,以上措施大家是自定义了net.tcp地址的点子实现了文件的上传,大家改变一下一贯用

http格局看看文件上传时候会变慢:

XML 5

看运维结果:

XML 6

呵呵…同样能兑现上传的效果,可是品质的落伍于营地址赋值地址,当然本人client情势正是透过ChannelFactory工厂创立,质量有所耗损是早晚的,那里同样告诫大家:

在大文件传输的时候我们最为是通过自定义地址达成客户端配置,当然大家前些天只是传递了1个简单的图片,对于大文件的上传大家供给愈多的安顿和性子优化。

相关文章

网站地图xml地图