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

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

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

      我的WCF之旅(6):在Winform Application中調(diào)用Duplex Service出現(xiàn)TimeoutException的原因和解決方案

      幾個(gè)星期之前寫(xiě)了一篇關(guān)于如何通過(guò)WCF進(jìn)行 雙向通信的文章([原創(chuàng)]我的WCF之旅(3):在WCF中實(shí)現(xiàn)雙向通信(Bi-directional Communication) ),在文章中我提供了一個(gè)如果在Console Application 調(diào)用Duplex WCF Service的Sample。前幾天有個(gè)網(wǎng)友在上面留言說(shuō),在沒(méi)有做任何改動(dòng)得情況下,把 作為Client的Console Application 換成Winform Application,運(yùn)行程序的時(shí)候總是出現(xiàn)Timeout的錯(cuò)誤。我覺(jué)得這是一個(gè)很好的問(wèn)題,通過(guò)這個(gè)問(wèn)題,我們可以更加深入地理解WCF的消息交換的機(jī)制。

      1.問(wèn)題重現(xiàn)

      首先我們來(lái)重現(xiàn)這個(gè)錯(cuò)誤,在這里我只寫(xiě)WinForm的代碼,其他的內(nèi)容請(qǐng)參考我的文章。Client端的Proxy Class(DuplexCalculatorClient)的定義沒(méi)有任何變化。我們先來(lái)定義用于執(zhí)行回調(diào)操作(Callback)的類(lèi)——CalculatorCallbackHandler.cs。代碼很簡(jiǎn)單,就是通過(guò)Message Box的方式顯示運(yùn)算的結(jié)果。

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.Windows.Forms;
      using Artech.DuplexWCFService.Contract;
      using System.ServiceModel;

      namespace Artech. WCFService.Client
      {
          [ServiceBehavior(ConcurrencyMode 
      = ConcurrencyMode.Multiple)]
          
      public class CalculatorCallbackHandler : ICalculatorCallback
          
      {
              
      ICalculatorCallback Members
          }

      }

      接著我們來(lái)設(shè)計(jì)我們的UI,很簡(jiǎn)單,無(wú)需多說(shuō)。


      代碼如下

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Text;
      using System.Windows.Forms;
      using System.Threading;

      namespace Artech. WCFService.Client
      {
          
      public partial class Form1 : Form
          
      {
              
      private DuplexCalculatorClient _calculator;
              
      private double _op1;
              
      private double _op2;
              
      public Form1()
              
      {
                  InitializeComponent();
              }

              
      private void Form1_Load(object sender, EventArgs e)
              
      {
                  
      this._calculator = new DuplexCalculatorClient(new System.ServiceModel.InstanceContext(new CalculatorCallbackHandler()));
              }

              
      private void Calculate()
              
      {
                  
      this._calculator.Add(this._op1, this._op2);
              }

              
      private void buttonCalculate_Click(object sender, EventArgs e)
              
      {
                  
      if (!double.TryParse(this.textBoxOp1.Text.Trim(), out this._op1))
                  
      {
                      MessageBox.Show(
      "Please enter a valid number","Error", MessageBoxButtons.OK,  MessageBoxIcon.Error);
                      
      this.textBoxOp1.Focus();
                  }

                  
      if (!double.TryParse(this.textBoxOp2.Text.Trim(), out this._op2))
                  
      {
                      MessageBox.Show(
      "Please enter a valid number","Error", MessageBoxButtons.OK,  MessageBoxIcon.Error);
                      
      this.textBoxOp1.Focus();
                  }

                  
      try
                  
      {
                      
      this.Calculate();
                  }

                  
      catch (Exception ex)
                  
      {
                      MessageBox.Show(ex.Message, 
      "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                  }
       
              }

          }

      }

      啟動(dòng)Host,然后隨啟動(dòng)Client,在兩個(gè)Textbox中輸入數(shù)字2和3,Click Calculate按鈕,隨后整個(gè)UI被鎖住,無(wú)法響應(yīng)用戶操作。一分后,出現(xiàn)下面的錯(cuò)誤。


      我們從上面的Screen Shot中可以看到這樣一個(gè)很有意思的現(xiàn)象,運(yùn)算結(jié)果被成功的顯示,顯示,但是有個(gè)Exception被拋出:”This request operation sent to http://localhost:6666/myClient/4f4ebfeb-5c84-45dc-92eb-689d631b337f did not receive a reply within the configured timeout (00:00:57.7300000). The time allotted to this operation may have been a portion of a longer timeout. This may be because the service is still processing the operation or because the service was unable to send a reply message. Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client.”。

      2.原因分析

      在我開(kāi)始分析為什么會(huì)造成上面的情況之前,我要申明一點(diǎn):由于找不到任何相關(guān)的資料,以下的結(jié)論是我從試驗(yàn)推導(dǎo)出來(lái),我不能保證我的分析是合理的,因?yàn)橛行┘?xì)節(jié)我自己都還不能自圓其說(shuō),我將在后面提到。我希望有誰(shuí)對(duì)此了解的人能夠指出我的問(wèn)題, 我將不勝感激。

      我們先來(lái)看看整個(gè)調(diào)用過(guò)程的Message Exchange過(guò)程,通過(guò)前面相關(guān)的介紹,我們知道WCF可以采用三種不同的Message Exchange Pattern(MEP)——One-way,Request/Response,Duplex。其實(shí)從本質(zhì)上講,One-way,Request/Response是兩種基本的MEP, Duplex可以看成是這兩種MEP的組合——兩個(gè)One-way,兩個(gè)Request/Response或者是一個(gè)One-way和一個(gè)Request/Response。在定義Service Contract的時(shí)候,如果我們沒(méi)有為某個(gè)Operation顯式指定為One-way (IsOneWay = true), 那么默認(rèn)采用Request/Response方式。我們現(xiàn)在的Sample就是由兩個(gè)Request/Response MEP組成的Duplex MEP。


      從上圖中我們可以很清楚地看出真?zhèn)€Message Exchange過(guò)程,Client調(diào)用Duplex Calculator Service,Message先從Client傳遞到Service,Service執(zhí)行Add操作,得到運(yùn)算結(jié)果之后,從當(dāng)前的OperationContext獲得Callback對(duì)象,發(fā)送一個(gè)Callback 請(qǐng)求道Client(通過(guò)在Client注冊(cè)的Callback Channel:http://localhost:6666/myClient)。但是,由于Client端調(diào)用Calculator Service是在主線程中,我們知道一個(gè)UI的程序的主線程一直處于等待的狀態(tài),它是不會(huì)有機(jī)會(huì)接收來(lái)自Service端的Callback請(qǐng)求的。但是由于Callback Operation是采用Request/Response方式調(diào)用的,所以它必須要收到來(lái)自Client端Reply來(lái)確定操作正常結(jié)束。這實(shí)際上形成了一個(gè)Deadlock,可以想象它用過(guò)也不能獲得這個(gè)Reply,所以在一個(gè)設(shè)定的時(shí)間內(nèi)(默認(rèn)為1分鐘),它會(huì)拋出Timeout 的Exception, Error Message就像下面這個(gè)樣子。

      ”This request operation sent to http://localhost:6666/myClient/4f4ebfeb-5c84-45dc-92eb-689d631b337f did not receive a reply within the configured timeout (00:00:57.7300000). The time allotted to this operation may have been a portion of a longer timeout. This may be because the service is still processing the operation or because the service was unable to send a reply message. Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client.”。

      3.解決方案

      方案1:多線程異步調(diào)用

      既然WinForm的主線程不能接受Service的Callback,那么我們就在另一個(gè)線程調(diào)用Calculator Service,在這個(gè)新的線程接受來(lái)自Service的Callback。

      于是我們改變Client的代碼:

      private void buttonCalculate_Click(object sender, EventArgs e)
              
      {
                  
      if (!double.TryParse(this.textBoxOp1.Text.Trim(), out this._op1))
                  
      {
                      MessageBox.Show(
      "Please enter a valid number","Error", MessageBoxButtons.OK,  MessageBoxIcon.Error);
                      
      this.textBoxOp1.Focus();
                  }


                  
      if (!double.TryParse(this.textBoxOp2.Text.Trim(), out this._op2))
                  
      {
                      MessageBox.Show(
      "Please enter a valid number","Error", MessageBoxButtons.OK,  MessageBoxIcon.Error);
                      
      this.textBoxOp1.Focus();
                  }

                  
      try
                  
      {
                      Thread newThread 
      = new Thread(new ThreadStart(this.Calculate));
                      newThread.Start();        
                  }

                  
      catch (Exception ex)
                  
      {
                      MessageBox.Show(ex.Message, 
      "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                  }
                   
              }

      通過(guò)實(shí)驗(yàn)證明,這種方式是可行的。

      方案2:采用One-way的方式調(diào)用Service 和Callback,既然是因?yàn)镋xception發(fā)生在不同在規(guī)定的時(shí)間內(nèi)不能正常地收到對(duì)應(yīng)的Reply,那種我就 允許你不必收到Reply就好了——實(shí)際上在本例中,對(duì)于Add方法,我們根本就不需要有返回結(jié)果,我們完全可以使用One-way的方式調(diào)用Operation。在這種情況下,我們只需要改變DuplexCalculator和CalculatorCallback的Service Contract定義就可以了。

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

      namespace Artech.DuplexWCFService.Contract
      {
          [ServiceContract(CallbackContract 
      = typeof(ICalculatorCallback))]
          
      public interface IDuplexCalculator
          
      {
              [OperationContract(IsOneWay 
      =true)]
              
      void Add(double x, double y);
          }

      }

      從Message Exchange的角度講,這種方式實(shí)際上是采用下面一種消息交換模式(MEP):

      進(jìn)一步地,由于Callback也沒(méi)有返回值,我們也可以把Callback操作也標(biāo)記為One-way.

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

      namespace Artech.DuplexWCFService.Contract
      {
          
      //[ServiceContract]
          public interface ICalculatorCallback
          
      {
              [OperationContract(IsOneWay 
      = true)]
              
      void  ShowResult(double x, double y, double result);
          }

      }

      那么現(xiàn)在的Message Exchange成為下面一種方式:

      實(shí)現(xiàn)證明這兩種方式也是可行的。

      4 .疑問(wèn)

      雖然直到現(xiàn)在,所有的現(xiàn)象都說(shuō)得過(guò)去,但是仍然有一個(gè)問(wèn)題不能得到解釋?zhuān)喝绻且驗(yàn)閃inform的主線程不能正常地接受來(lái)自Service的Callback才導(dǎo)致了Timeout Exception,那為什么Callback操作能過(guò)正常執(zhí)行呢?而且通過(guò)我的實(shí)驗(yàn)證明他基本上是在拋出Exception的同時(shí)執(zhí)行的。(參考第2個(gè)截圖)

      WCF相關(guān)內(nèi)容:
      [原創(chuàng)]我的WCF之旅(1):創(chuàng)建一個(gè)簡(jiǎn)單的WCF程序
      [原創(chuàng)]我的WCF之旅(2):Endpoint Overview
      [原創(chuàng)]我的WCF之旅(3):在WCF中實(shí)現(xiàn)雙向通信(Bi-directional Communication)
      [原創(chuàng)]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I
      [原創(chuàng)]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II
      [原創(chuàng)]我的WCF之旅(5):Service Contract中的重載(Overloading)
      [原創(chuàng)]我的WCF之旅(6):在Winform Application中調(diào)用Duplex Service出現(xiàn)TimeoutException的原因和解決方案
      [原創(chuàng)]我的WCF之旅(7):面向服務(wù)架構(gòu)(SOA)和面向?qū)ο缶幊蹋∣OP)的結(jié)合——如何實(shí)現(xiàn)Service Contract的繼承
      [原創(chuàng)]我的WCF之旅(8):WCF中的Session和Instancing Management
      [原創(chuàng)]我的WCF之旅(9):如何在WCF中使用tcpTrace來(lái)進(jìn)行Soap Trace
      [原創(chuàng)]我的WCF之旅(10): 如何在WCF進(jìn)行Exception Handling
      [原創(chuàng)]我的WCF之旅(11):再談WCF的雙向通訊-基于Http的雙向通訊 V.S. 基于TCP的雙向通訊

      [原創(chuàng)]我的WCF之旅(12):使用MSMQ進(jìn)行Reliable Messaging
      [原創(chuàng)]我的WCF之旅(13):創(chuàng)建基于MSMQ的Responsive Service

      posted @ 2007-03-29 00:34  Artech  閱讀(28189)  評(píng)論(52)    收藏  舉報(bào)
      主站蜘蛛池模板: 日韩精品中文字幕亚洲| 国产成人午夜精品永久免费| 国产成人精品午夜二三区| 中文字幕精品亚洲二区| 乱码精品一区二区三区| 成人免费xxxxx在线观看| 日韩福利片午夜免费观着| 国产女人喷潮视频免费| 少妇高潮灌满白浆毛片免费看| 国产激情一区二区三区四区| 免费费很色大片欧一二区| 欧美精品亚洲精品日韩专| 成人午夜av在线播放| 久久男人av资源站| 亚洲欧美自偷自拍视频图片| 波多野结衣久久一区二区| 久久99精品久久久久久青青| 国产三级国产精品久久成人| 午夜福利精品国产二区| 精选国产av精选一区二区三区 | 免费无码AV一区二区波多野结衣| 少妇人妻互换不带套| 性色av不卡一区二区三区| 人妻中文字幕亚洲精品| 精品久久久久久无码人妻蜜桃| 一区二区三区AV波多野结衣| 亚洲精品一区二区三区蜜臀| 一二三四中文字幕日韩乱码| 99国产精品欧美一区二区三区 | 亚洲精品99久久久久久欧美版| 四虎永久精品免费视频| 日本视频高清一区二区三区| 亚洲午夜激情久久加勒比| 又湿又紧又大又爽A视频男| 午夜精品区| 久久亚洲精品亚洲人av| 狼人大伊人久久一区二区| 日韩有码中文字幕国产| 成人动漫综合网| 精品国精品国自产在国产| 欧美成人www免费全部网站|