5. WCF 异步调用
原文:http://www.rainsts.net/article.asp?id=432
编写步骤:
1. 创建服务契约。
我们为 GetData方法添加了 BeginGetData和 EndGetData两个在 .NET SDK 中 "常见" 的异步操作方法。注意 BeginGetData方法中我们添加了异步声明,而 EndGetData 方法没有。还有就是要注意异步版本方法的参数。
<ServiceContract(SessionMode:=SessionMode.Required)> _
Public Interface IService1
<OperationContract()> _
Function GetData(ByVal value As Integer) As String
<OperationContract(asyncpattern:=True)> _
Function BeginGetData(ByVal value As Integer, ByVal callBack As AsyncCallback, ByVal state As Object) As IAsyncResult
Function EndGetData(ByVal ar As IAsyncResult) As String
End Interface
Public Interface IService1
<OperationContract()> _
Function GetData(ByVal value As Integer) As String
<OperationContract(asyncpattern:=True)> _
Function BeginGetData(ByVal value As Integer, ByVal callBack As AsyncCallback, ByVal state As Object) As IAsyncResult
Function EndGetData(ByVal ar As IAsyncResult) As String
End Interface
2. 实现服务契约。
你可能注意到了,我们并没有创建 Add 的委托原型,也没有 "真正" 实现 BeginAdd 和 EndAdd。这是因为消息交换会 "异步" 调用 Add 方法,所有的异步版本方法只是用来创建消息声明而已。
Public Class Service1
Implements IService1
Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
Console.WriteLine("服务器方法 GetData 开始执行: {0}", DateTime.Now)
Debug.WriteLine("服务器方法 GetData 开始执行: " & DateTime.Now)
Thread.Sleep(5000)
Dim str As String = String.Format("You entered: {0}", value)
Console.WriteLine("服务器方法 GetData 执行完成: {0}", DateTime.Now)
Debug.WriteLine("服务器方法 GetData 执行完成: " & DateTime.Now)
Return str
End Function
Public Function BegionGetData(ByVal value As Integer, ByVal callback As System.AsyncCallback, ByVal state As Object) As IAsyncResult Implements IService1.BeginGetData
Throw New Exception("The method or operation is not implemented.")
End Function
Public Function EndGetData(ByVal ar As System.IAsyncResult) As String Implements IService1.EndGetData
Throw New Exception("The method or operation is not implemented.")
End Function
End Class
Implements IService1
Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
Console.WriteLine("服务器方法 GetData 开始执行: {0}", DateTime.Now)
Debug.WriteLine("服务器方法 GetData 开始执行: " & DateTime.Now)
Thread.Sleep(5000)
Dim str As String = String.Format("You entered: {0}", value)
Console.WriteLine("服务器方法 GetData 执行完成: {0}", DateTime.Now)
Debug.WriteLine("服务器方法 GetData 执行完成: " & DateTime.Now)
Return str
End Function
Public Function BegionGetData(ByVal value As Integer, ByVal callback As System.AsyncCallback, ByVal state As Object) As IAsyncResult Implements IService1.BeginGetData
Throw New Exception("The method or operation is not implemented.")
End Function
Public Function EndGetData(ByVal ar As System.IAsyncResult) As String Implements IService1.EndGetData
Throw New Exception("The method or operation is not implemented.")
End Function
End Class
客户端调用:
Sub Main()
Dim url As String = "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex"
Dim host As New System.ServiceModel.ServiceHost(GetType(WcfServiceLibrary1.Service1))
host.AddServiceEndpoint(GetType(WcfServiceLibrary1.IService1), New System.ServiceModel.WSHttpBinding, url)
host.Open()
Console.WriteLine(host.State.ToString)
Dim c = New System.ServiceModel.ChannelFactory(Of WcfServiceLibrary1.IService1)(New System.ServiceModel.WSHttpBinding, url)
Dim s = c.CreateChannel
Console.WriteLine("客户端调用 BeginGetData: {0}", DateTime.Now)
Debug.WriteLine("客户端调用 BeginGetData: " & DateTime.Now)
Dim ar As IAsyncResult = s.BeginGetData(1, New AsyncCallback(AddressOf Print), Nothing)
Console.WriteLine("客户端调用 BeginGetData 完成: {0}", DateTime.Now)
Debug.WriteLine("客户端调用 BeginGetData 完成: " & DateTime.Now)
' Console.WriteLine(s.EndGetData(ar))
' Console.WriteLine("客户端调用 EndGetData 完成: {0}", DateTime.Now)
Console.WriteLine("执行完成!")
Debug.WriteLine("执行完成!")
Console.ReadLine()
End Sub
Sub Print(ByVal ar As IAsyncResult)
Console.WriteLine("异步执行完成……")
Debug.WriteLine("异步执行完成……")
End Sub
Dim url As String = "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex"
Dim host As New System.ServiceModel.ServiceHost(GetType(WcfServiceLibrary1.Service1))
host.AddServiceEndpoint(GetType(WcfServiceLibrary1.IService1), New System.ServiceModel.WSHttpBinding, url)
host.Open()
Console.WriteLine(host.State.ToString)
Dim c = New System.ServiceModel.ChannelFactory(Of WcfServiceLibrary1.IService1)(New System.ServiceModel.WSHttpBinding, url)
Dim s = c.CreateChannel
Console.WriteLine("客户端调用 BeginGetData: {0}", DateTime.Now)
Debug.WriteLine("客户端调用 BeginGetData: " & DateTime.Now)
Dim ar As IAsyncResult = s.BeginGetData(1, New AsyncCallback(AddressOf Print), Nothing)
Console.WriteLine("客户端调用 BeginGetData 完成: {0}", DateTime.Now)
Debug.WriteLine("客户端调用 BeginGetData 完成: " & DateTime.Now)
' Console.WriteLine(s.EndGetData(ar))
' Console.WriteLine("客户端调用 EndGetData 完成: {0}", DateTime.Now)
Console.WriteLine("执行完成!")
Debug.WriteLine("执行完成!")
Console.ReadLine()
End Sub
Sub Print(ByVal ar As IAsyncResult)
Console.WriteLine("异步执行完成……")
Debug.WriteLine("异步执行完成……")
End Sub
输出结果:
客户端调用 BeginGetData: 2009-11-23 17:03:34
客户端调用 BeginGetData 完成: 2009-11-23 17:03:34
执行完成!
服务器方法 GetData 开始执行: 2009-11-23 17:03:34
服务器方法 GetData 执行完成: 2009-11-23 17:03:39
异步执行完成……
最后需要注意的是,我们必须使用支持 Session 的 Binding 对象 (BasicHttpBinding 会抛出异常)。
附:其实最简单的办法不是手工添加 AsyncPattern / BeginXXX / EndXXX,而是手工使用 svcutil.exe 生成客户端代理,记住加上 "/async" 参数。不过,我还是觉得写代码爽些!
附:其实最简单的办法不是手工添加 AsyncPattern / BeginXXX / EndXXX,而是手工使用 svcutil.exe 生成客户端代理,记住加上 "/async" 参数。不过,我还是觉得写代码爽些!