閱讀517 返回首頁    go 阿裏雲 go 技術社區[雲棲]


如何在調用WCF服務之前彈出一個確認對話框?

昨天有人在微博上問我如下一個問題:

老蔣,客戶端調用wcf的一個接口函數時,有沒有什麼辦法可以先彈出一個確認框,確認後再執行調用。因為這個接口函數再很多地方都執行了調用,所以我想在某個入口進行統一地彈出一個確認框...

20121007100122114.png

其實這個問題可以通過WCF的擴展來完成,具體來說這個擴展涉及到一個我們不太常用的組件“InteractiveChannelInitializer”,在我的《WCF全麵解析》中對它有過概括性的介紹。InteractiveChannelInitializer實現了接口IInteractiveChannelInitializer,從名稱可以看出這是一個“交互性”的“信道初始化器”,在一般情況下我們用它來動態地指定客戶端調用憑證(比如在彈出的登錄對話框中輸入用戶名和密碼)。而上麵這個問題就可以通過自定義InteractiveChannelInitializer來實現,我為此寫了一個簡單的實例(源代碼從這裏下載)。

右圖所示的是實例的運行界麵。我們以Windows Form應用的方式編寫了一個“計算器”,計算結果通過調用WCF服務來獲取。在每次調用服務之前都會彈出一個確認對話框,真正的服務調用隻有在用戶確認之後方能進行。

用於實現“服務調用確認”的自定義InteractiveChannelInitializer(InvocationConfirmationInteractiveChannelInitializer)定義如下。我們在BeginDisplayInitializationUI方法中彈出一個確認對話框,並將用戶的確認選擇封裝到一個簡單的AsyncResult對象中返回。在EndDisplayInitializationUI方法中,通過AsyncResult對象確認用戶是否取消本次服務調用,如果是則拋出一個自定義的InvocationCancelException異常。

   1: public class InvocationConfirmationInteractiveChannelInitializer : IInteractiveChannelInitializer
   2: {
   3:     public const string ConfirmMessage = "程序執行過程涉及到WCF服務調用,是否繼續?";
   4:     public IAsyncResult BeginDisplayInitializationUI(IClientChannel channel, AsyncCallback callback, object state)
   5:     {
   6:         bool cancel = MessageBox.Show(ConfirmMessage, "WCF服務調用確認", MessageBoxButtons.YesNo) == DialogResult.No;
   7:         return new SimpleAsynsResult(cancel);
   8:     }
   9:  
  10:     public void EndDisplayInitializationUI(IAsyncResult result)
  11:     {
  12:         SimpleAsynsResult asyncResult = (SimpleAsynsResult)result;
  13:         if((bool)asyncResult.AsyncState)
  14:         {
  15:             throw new InvocationCancelException("WCF服務調用被取消");
  16:         }
  17:     }
  18: }
  19:  
  20: public class SimpleAsynsResult:IAsyncResult
  21: {
  22:     public SimpleAsynsResult(object state)
  23:     {
  24:         this.AsyncState = state;
  25:     }
  26:  
  27:     public object AsyncState { get; private set; }
  28:     public WaitHandle AsyncWaitHandle { get; private set; }
  29:     public bool CompletedSynchronously
  30:     {
  31:         get { return true; }
  32:     }
  33:     public bool IsCompleted
  34:     {
  35:         get { return true; }
  36:     }
  37: }

我們通過一個自定義的ContractBehavior(InvocationConfirmationBehaviorAttribute )將上麵自定義的InvocationConfirmationInteractiveChannelInitializer應用到客戶端運行時。如下麵的代碼片斷所示,在實現的ApplyClientBehavior方法中,我們創建了一個InvocationConfirmationInteractiveChannelInitializer對象並將其添加到客戶端運行時的InteractiveChannelInitializers集合中。

   1: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
   2: public class InvocationConfirmationBehaviorAttribute : Attribute, IContractBehavior
   3: {
   4:     public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
   5:     public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   6:     {
   7:         clientRuntime.InteractiveChannelInitializers.Add(new InvocationConfirmationInteractiveChannelInitializer());
   8:     }
   9:     public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { }
  10:     public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { }
  11: }

以特性形式定義的InvocationConfirmationBehaviorAttribute直接以如下的方式直接應用到作為服務契約的ICalcualtor接口中:

   1: [ServiceContract(Name = "CalculatorService", Namespace ="https://www.artech.com/")]
   2: 
   3: public interface ICalculator
   4: {
   5:     [OperationContract]
   6:     double Add(double x, double y);
   7: }

那麼在進行服務調用的時候,確認對話框會自動彈出來。如果用戶選擇終止當前服務調用,那麼InvocationCancelException異常會被拋出來,我們隻需要捕捉該類型的異常即可。如下所示的是“=”按鈕的Click事件代碼:

   1: public partial class Form1 : Form
   2: {
   3:     //其他成員
   4:     private void buttonCalculate_Click(object sender, EventArgs e)
   5:     {
   6:         this.textBoxResult.Text = string.Empty;
   7:         using (ChannelFactory<ICalculator> channelfactory = new ChannelFactory<ICalculator>("calculatorservice"))
   8:         {
   9:             ICalculator calculator = channelfactory.CreateChannel();
  10:             try
  11:             {
  12:                 double op1 = double.Parse(this.textBoxOp1.Text);
  13:                 double op2 = double.Parse(this.textBoxOp2.Text);
  14:                 double result = calculator.Add(op1,op2);
  15:                 this.textBoxResult.Text = result.ToString();
  16:             }
  17:             catch (InvocationCancelException)
  18:             {
  19:             }
  20:             catch (Exception ex)
  21:             {
  22:                 MessageBox.Show(ex.Message);
  23:             }
  24:         }
  25:     }
  26: }

作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-25 16:33:44

  上一篇:go  ASP.NET MVC的Razor引擎:RazorViewEngine
  下一篇:go  利用ASP.NET SiteMap生成與Bootstrap"兼容"菜單