<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      傳說中的WCF(9):流與文件傳輸

      在使用Socket/TCP來傳輸文件,弄起來不僅會有些復(fù)雜,而且較經(jīng)典的“粘包”問題有時候會讓人火冒七丈。如果你不喜歡用Socket來傳文件,不妨試試WCF,WCF的流模式傳輸還是相當強大和相當實用的。

      因為開啟流模式是基于綁定的,所以,它會影響到整個終結(jié)點的操作協(xié)定。如果你不記得或者說不喜歡背書,不想去記住哪些綁定支持流模式,可以通過以下方法:

      因為開啟流模式,主要是設(shè)置一個叫TransferMode的屬性,所以,你看看哪些Binding的派生類有這個屬性就可以了。

      TransferMode其實是一個舉枚,看看它的幾個有效值:

        1,Buffered:緩沖模式,說白了就是在內(nèi)存中緩沖,一次調(diào)用就把整個消息讀/寫完,也就是我們最常用的方式,就是普通的操作協(xié)定的調(diào)用方式;
        2,StreamedRequest:只是在請求的時候使用流,說簡單一點就是在傳入方法的參數(shù)使用流,如 int MyMethod(System.IO.Stream stream);
        3,StreamedResponse:就是操作協(xié)定方法返回一個流,如 Stream MyMethod(string file_name);
      一般而言,如果使用流作為傳入?yún)?shù),最好不要使用多個參數(shù),如這樣:

      bool TransferFile(Stream stream, string name);

      上面的方法就有了兩個in參數(shù)了,最好別這樣,為什么?有空的話,自己試試就知道了。那如果要傳入更多的數(shù)據(jù),怎么辦?呵呵,還記得消息協(xié)定嗎?

       

      好的,下面我們來弄一個上傳MP3文件的實例。實例主要的工作是從客戶端上傳一個文件到服務(wù)器。

      老規(guī)矩,一般做這種應(yīng)用程序,應(yīng)該先做服務(wù)器端。

          class Program
          {
              static void Main(string[] args)
              {
                  // 服務(wù)器基址  
                  Uri baseAddress = new Uri("http://localhost:1378/services");
                  // 聲明服務(wù)器主機  
                  using (ServiceHost host = new ServiceHost(typeof(MyService), baseAddress))
                  {
                      // 添加綁定和終結(jié)點  
                      BasicHttpBinding binding = new BasicHttpBinding();
                      // 啟用流模式  
                      binding.TransferMode = TransferMode.StreamedRequest;
                      binding.MaxBufferSize = 1024;
                      // 接收消息的最大范圍為500M  
                      binding.MaxReceivedMessageSize = 500 * 1024 * 1024;
                      host.AddServiceEndpoint(typeof(IService), binding, "/test");
                      // 添加服務(wù)描述  
                      host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
                      try
                      {
                          // 打開服務(wù)  
                          host.Open();
                          Console.WriteLine("服務(wù)已啟動。");
                      }
                      catch (Exception ex)
                      {
                          Console.WriteLine(ex.Message);
                      }
                      Console.ReadKey();
                  }
              }
          }
          [ServiceContract(Namespace = "MyNamespace")] 
          class IService
          {
              [OperationContract]
              bool UpLoadFile(System.IO.Stream streamInput); 
          }
          class MyService : IService
          {
              public bool UpLoadFile(System.IO.Stream streamInput)
              {
                  bool isSuccessed = false;
                  try
                  {
                      using (FileStream outputStream = new FileStream("test.mp3", FileMode.OpenOrCreate, FileAccess.Write))
                      {
                          // 我們不用對兩個流對象進行讀寫,只要復(fù)制流就OK  
                          streamInput.CopyTo(outputStream);
                          outputStream.Flush();
                          isSuccessed = true;
                          Console.WriteLine("在{0}接收到客戶端發(fā)送的流,已保存到test.map3。", DateTime.Now.ToLongTimeString());
                      }
                  }
                  catch
                  {
                      isSuccessed = false;
                  }
                  return isSuccessed;
              }
          }

      從例子我們看到,操作方法是這樣定義的:

      bool UpLoadFile(System.IO.Stream streamInput) 

      因為它的返回值是bool類型,不是流,而只是傳入的參數(shù)是流,因為在配置綁定時,應(yīng)用使用StreamedRequest。

      BasicHttpBinding binding = new BasicHttpBinding();  
      // 啟用流模式  
      binding.TransferMode = TransferMode.StreamedRequest;  
      binding.MaxBufferSize = 1024;  
      // 接收消息的最大范圍為500M  
      binding.MaxReceivedMessageSize = 500 * 1024 * 1024;

      現(xiàn)在,我們做客戶端,因為要選擇文件上傳,所以使用wpf項目類型。

      在窗口上拖兩個按鈕,一個用來選擇文件,另一個用于啟動文件上傳,另外兩個Label就是用來顯示一些文本。

      而窗體的實現(xiàn)代碼部分如下:

          /// <summary>
          /// Interaction logic for MainWindow.xaml
          /// </summary>
          public partial class MainWindow : Window
          {
              public MainWindow()
              {
                  InitializeComponent();
              }
      
              private void button1_Click(object sender, RoutedEventArgs e)
              {
                  OpenFileDialog dlg = new OpenFileDialog();
                  dlg.Filter = "MP3音頻文件|*.mp3";
                  if (dlg.ShowDialog() == true)
                  {
                      this.label1.Content = dlg.FileName;
                      this.label2.Content = "準備就緒。";
                  }
              }
      
              private void button2_Click(object sender, RoutedEventArgs e)
              {
                  if (!File.Exists((string)this.label1.Content))
                  {
                      return;
                  }
                  FileStream fs = new FileStream((string)this.label1.Content, FileMode.Open, FileAccess.Read);
                  ServiceReference1.ServiceClient cl = new ServiceReference1.ServiceClient();
                  this.button2.IsEnabled = false;
                  bool res = cl.UpLoadFile(fs);
                  this.button2.IsEnabled = true;
                  if (res == true)
                      this.label2.Content = "上傳完成。";
              }
          }

      記住,千萬別忘了引用服務(wù)?。。。。。。。。。。。。。。。。。。?/strong>

      現(xiàn)在可以運行了。

      不知道大家注意到?jīng)]有?在服務(wù)器端代碼中,我們設(shè)置了綁定的MaxReceivedMessageSize為500M,這一般是在消息模式下,為了安全(防止惡意攻擊)而設(shè)置的限制,那么,如果使用了流模式,這個值還用不用設(shè)置。想驗證也很簡單,把這行代碼注釋掉,再運行試試。

                      // 接收消息的最大范圍為500M  
                      //binding.MaxReceivedMessageSize = 500 * 1024 * 1024;

      運行程序,結(jié)發(fā)現(xiàn),是不成功的,你看看我下面的截圖,只傳了40多K,還遠著呢。

      因此,MaxReceivedMessageSize還是要設(shè)置的,不然,它的默認值太小了,傳不了大文件。

      現(xiàn)在又希望上面的例子多一個功能,文件上傳后,依然按客戶端原文件命名,而不是test.mp3,這就意味著操作方法要傳兩個參數(shù),前面我提了一下,不要忘了消息協(xié)定,而這個我們可以通過消息協(xié)定來完成。

      因此,服務(wù)器端代碼要改一改了,首先,定義一個消息協(xié)定。

          [MessageContract]
          public class TransferFileMessage
          {
              [MessageHeader]
              public string File_Name; //文件名  
              [MessageBodyMember]
              public Stream File_Stream; //文件流  
          } 

      接著操作方法也要改動。

              public bool UpLoadFile(TransferFileMessage tMsg)
              {
                  bool isSuccessed = false;
                  if (tMsg == null || tMsg.File_Stream == null)
                  {
                      return false;
                  }
                  try
                  {
                      using (FileStream outputStream = new FileStream(tMsg.File_Name, FileMode.OpenOrCreate, FileAccess.Write))
                      {
                          // 我們不用對兩個流對象進行讀寫,只要復(fù)制流就OK  
                          tMsg.File_Stream.CopyTo(outputStream);
                          outputStream.Flush();
                          isSuccessed = true;
                          Console.WriteLine("在{0}接收到客戶端發(fā)送的流,已保存到{1}。", DateTime.Now.ToLongTimeString(), tMsg.File_Name);
                      }
                  }
                  catch
                  {
                      isSuccessed = false;
                  }
                  return isSuccessed;
              }

      在測試服務(wù)器端運行成功后,要記得更新客戶端的引用。

      可是,遺憾的是,服務(wù)沒有正常啟動。為什么呢?想一想,如果光看錯誤消息,你可能不太明白。我給你20秒的時間想一想,為什么上面的代碼不能正常運行。

      好了,其實,問題就出在操作協(xié)定的定義上:

              [OperationContract]
              bool UpLoadFile(TransferFileMessage tMsg);  

      我們前面說過,什么叫雙工,有來有往,是吧?對啊,上面的方法是有傳入?yún)?shù),也有返回值,有來有去啊,是雙工啊,為啥不行了呢?

      哈哈,問題就在于我們使用了消息協(xié)定,在這種前提下,我們的方法就不能隨便定義了,使用消息協(xié)定的方法,如果:

      a、消息協(xié)定作為傳入?yún)?shù),則只能有一個參數(shù),以下定義是錯誤的:

      void Reconcile(BankingTransaction bt1, BankingTransaction bt2);

      b、除非你返回值為void,如不是,那你必須返回一個消息協(xié)定,bool UpLoadFile(TransferFileMessage tMsg)我們這個定義明顯不符合要求。

      那如何解決呢?我們要再定義一個用于返回的消息協(xié)定。

          [MessageContract]
          public class ResultMessage
          {
              [MessageHeader]
              public string ErrorMessage;
              [MessageBodyMember]
              public bool IsSuccessed;
          }  

      然后把上面的操作方法也改一下。

              public ResultMessage UpLoadFile(TransferFileMessage tMsg)
              {
                  ResultMessage rMsg = new ResultMessage();
                  if (tMsg == null || tMsg.File_Stream == null)
                  {
                      rMsg.ErrorMessage = "傳入的參數(shù)無效。";
                      rMsg.IsSuccessed = false;
                      return rMsg;
                  }
                  try
                  {
                      using (FileStream outputStream = new FileStream(tMsg.File_Name, FileMode.OpenOrCreate, FileAccess.Write))
                      {
                          // 我們不用對兩個流對象進行讀寫,只要復(fù)制流就OK  
                          tMsg.File_Stream.CopyTo(outputStream);
                          outputStream.Flush();
                          rMsg.IsSuccessed = true;
                          Console.WriteLine("在{0}接收到客戶端發(fā)送的流,已保存到{1}。", DateTime.Now.ToLongTimeString(), tMsg.File_Name);
                      }
                  }
                  catch (Exception ex)
                  {
                      rMsg.IsSuccessed = false;
                      rMsg.ErrorMessage = ex.Message;
                  }
                  return rMsg;
              }

      現(xiàn)在你試試能不能正常運行?好了,客戶端記得更新引用,而且,客戶端的代碼也要修改。

              private void button2_Click(object sender, RoutedEventArgs e)
              {
                  if (!File.Exists((string)this.label1.Content))
                  {
                      return;
                  }
                  FileStream fs = new FileStream((string)this.label1.Content, FileMode.Open, FileAccess.Read);
                  ServiceReference1.ServiceClient cl = new ServiceReference1.ServiceClient();
                  this.button2.IsEnabled = false;
                  bool isSuccessed = false;
                  var response = cl.UpLoadFile(System.IO.Path.GetFileName((string)this.label1.Content), fs, out isSuccessed);
                  this.button2.IsEnabled = true;
                  if (isSuccessed == true)
                      this.label2.Content = "上傳完成。";
                  else
                      this.label2.Content = "錯誤信息:" + response;
              }

      現(xiàn)在再來測測吧。

      再看看服務(wù)器端。

      哈哈,現(xiàn)在就完美解決了。

      posted @ 2016-08-09 11:05  閆寶平  閱讀(315)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲熟妇精品一区二区| 久久亚洲av成人无码软件| 亚洲大尺度无码专区尤物| 天天躁日日躁狠狠躁中文字幕| 国产精品人妻中文字幕| 男人用嘴添女人下身免费视频| 亚洲综合伊人久久大杳蕉| 中文人妻av高清一区二区| 婷婷综合亚洲| 中文人妻AV高清一区二区| 午夜福利激情一区二区三区| 99精品国产一区二区三区不卡 | 蜜芽久久人人超碰爱香蕉| 特级做a爰片毛片免费看无码| 天堂久久久久VA久久久久| 沂南县| 国产精品国产精品偷麻豆 | 欧美视频免费一区二区三区 | 亚洲高清日韩专区精品| 丰满爆乳一区二区三区| 东京热人妻中文无码| 亚洲一区久久蜜臀av| 国产欧美一区二区精品久久久 | 亚洲精品综合一区二区在线| 乱60一70归性欧老妇| 少妇人妻av毛片在线看| 亚洲国内精品一区二区| 丝袜美腿一区二区三区| 黄又色又污又爽又高潮| 国产精品多p对白交换绿帽| 久久久精品人妻一区二区三区蜜桃| 久久婷婷成人综合色| 国产伦精区二区三区视频| 最好看的中文字幕国语| 欧美成人精品手机在线| 国产成人无码免费视频麻豆| 国产资源精品中文字幕| 国产一区二区日韩在线| 中文字幕人妻丝袜美腿乱| 无码专区 人妻系列 在线 | 亚洲国产美女精品久久久|