[ 2007-04-01 20:59:13 | 作者: yuhen ]
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" 参数。 |
|