[WCF 学习笔记] 7. 异步调用

WCF 的异步调用是基于消息交换(Message Exchange)来实现的,和我们通常使用委托来实现异步调用有所不同。

编写步骤:

1. 创建服务契约。

[ServiceContract(SessionMode=SessionMode.Required)]
public interface ICalculate
{
  [OperationContract]
  int Add(int a, int b);
}


2. 为契约方法添加异步版本。

我们为 Add 方法添加了 BeginAdd 和 EndAdd 两个在 .NET SDK 中 "常见" 的异步操作方法。注意 BeginAdd 方法中我们添加了异步声明,而 EndAdd 方法没有。还有就是要注意异步版本方法的参数。

[ServiceContract(SessionMode=SessionMode.Required)]
public interface ICalculate
{
  [OperationContract]
  int Add(int a, int b);

  [OperationContract(AsyncPattern=true)]
  IAsyncResult BeginAdd(int a, int b, AsyncCallback callBack, object state);

  int EndAdd(IAsyncResult ar);
}


3. 实现服务契约。

你可能注意到了,我们并没有创建 Add 的委托原型,也没有 "真正" 实现 BeginAdd 和 EndAdd。这是因为消息交换会 "异步" 调用 Add 方法,所有的异步版本方法只是用来创建消息声明而已。

public class CalculateService : ICalculate
{
  public int Add(int a, int b)
  {
    Thread.Sleep(5000);
    Console.WriteLine(OperationContext.Current.SessionId);
    return a + b;
  }

  public IAsyncResult BeginAdd(int a, int b, AsyncCallback callBack, object state)
  {
    throw new Exception("The method or operation is not implemented.");
  }

  public int EndAdd(IAsyncResult ar)
  {
    throw new Exception("The method or operation is not implemented.");
  }
}


4. 我们给一个完整版本,看看执行结果。

[ServiceContract]
public interface ICalculate
{
  [OperationContract]
  int Add(int a, int b);

  [OperationContract(AsyncPattern = true)]
  IAsyncResult BeginAdd(int a, int b, AsyncCallback callBack, object state);

  int EndAdd(IAsyncResult ar);
}

public class CalculateService : ICalculate
{
  public int Add(int a, int b)
  {
    Console.WriteLine("服务器方法 Add 开始执行: {0}", DateTime.Now);
    try
    {
      Thread.Sleep(5000);
      return a + b;
    }
    finally
    {
      Console.WriteLine("服务器方法 Add 执行完成: {0}", DateTime.Now);
    }
  }

  public IAsyncResult BeginAdd(int a, int b, AsyncCallback callBack, object state)
  {
    throw new Exception("The method or operation is not implemented.");
  }

  public int EndAdd(IAsyncResult ar)
  {
    throw new Exception("The method or operation is not implemented.");
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(CalculateService));
      host.AddServiceEndpoint(typeof(ICalculate), new WSHttpBinding(),
       "http://localhost:8080/calc");

      host.Open();
    });

    ICalculate channel = ChannelFactory<ICalculate>.CreateChannel(new WSHttpBinding(),
     new EndpointAddress("http://localhost:8080/calc"));

    using (channel as IDisposable)
    {
      Console.WriteLine("客户端调用 BeginAdd: {0}", DateTime.Now);
      IAsyncResult ar = channel.BeginAdd(1, 2, delegate { Console.WriteLine("CallBack..."); }, null);
      Console.WriteLine("客户端调用 BeginAdd 完成: {0}", DateTime.Now);
      Console.WriteLine(channel.EndAdd(ar));
      Console.WriteLine("客户端调用 EndAdd 完成: {0}", DateTime.Now);
    }
  }
}


输出:
客户端调用 BeginAdd: 2007-4-1 20:56:47
客户端调用 BeginAdd 完成: 2007-4-1 20:56:47
服务器方法 Add 开始执行: 2007-4-1 20:56:49
服务器方法 Add 执行完成: 2007-4-1 20:56:54
3
客户端调用 EndAdd 完成: 2007-4-1 20:56:55
CallBack...

最后需要注意的是,我们必须使用支持 Session 的 Binding 对象 (BasicHttpBinding 会抛出异常)。

附:其实最简单的办法不是手工添加 AsyncPattern / BeginXXX / EndXXX,而是手工使用 svcutil.exe 生成客户端代理,记住加上 "/async" 参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值