• 如何在调用WCF服务之前弹出一个确认框?


    昨天有人在微博上问我如下一个问题:

    老蒋,客户端调用wcf的一个接口函数时,有没有什么办法可以先弹出一个确认框,确认后再执行调用。因为这个接口函数再很多地方都执行了调用,所以我想在某个入口进行统一地弹出一个确认框...

    其实这个问题可以通过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 ="http://www.artech.com/")]
       2: [InvocationConfirmationBehavior]
       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: }
    作者:Artech
    出处:http://artech.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    记一次排查tomcat耗费CPU过高的经历
    记录一次PHP项目报502的问题
    工作职责与工作协调
    如何提升团队效率
    接手老项目的方法总结
    如何快速确定需求的技术实现方案
    PHP中的赋值-引用or传值?
    性能优化-开发流程中的性能优化
    一周阅读列表(20131111-20131117)
    一周阅读列表(20131104-20131110)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2713629.html
Copyright © 2020-2023  润新知