如何:以异步方式调用 WCF 服务操作
本文介绍客户端如何以异步方式访问服务操作。 本文中的服务可实现 ICalculator
接口。 通过使用事件驱动的异步调用模型,客户端可以对此接口异步调用操作。 (有关基于事件的异步调用模型的详细信息,请参阅使用基于事件的异步模式进行多线程编程)。 有关如何在服务中异步调用操作的示例,请参阅如何:以异步方式实现服务操作。 有关同步和异步操作的详细信息,请参阅同步和异步操作。
注意
使用 ChannelFactory<TChannel> 时,不支持事件驱动的异步调用模型。 有关使用 ChannelFactory<TChannel> 进行异步调用的信息,请参阅如何:使用通道工厂以异步方式调用操作。
过程
以异步方式调用 WCF 服务操作
运行同时带有
/async
和/tcv:Version35
命令选项的 ServiceModel 元数据实用工具 (Svcutil.exe),如下面的命令所示。svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples http://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35
除了同步操作和基于委托的标准异步操作之外,此操作还会生成 WCF 客户端类,其中包含以下内容:
两个与基于事件的异步调用方法一起使用的
<operationName>``Async
操作。 例如:public void AddAsync(double n1, double n2) { this.AddAsync(n1, n2, null); } public void AddAsync(double n1, double n2, object userState) { if ((this.onBeginAddDelegate == null)) { this.onBeginAddDelegate = new BeginOperationDelegate(this.OnBeginAdd); } if ((this.onEndAddDelegate == null)) { this.onEndAddDelegate = new EndOperationDelegate(this.OnEndAdd); } if ((this.onAddCompletedDelegate == null)) { this.onAddCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnAddCompleted); } base.InvokeAsync(this.onBeginAddDelegate, new object[] { n1, n2}, this.onEndAddDelegate, this.onAddCompletedDelegate, userState); }
Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double) Me.AddAsync(n1, n2, Nothing) End Sub Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double, ByVal userState As Object) If (Me.onBeginAddDelegate Is Nothing) Then Me.onBeginAddDelegate = AddressOf Me.OnBeginAdd End If If (Me.onEndAddDelegate Is Nothing) Then Me.onEndAddDelegate = AddressOf Me.OnEndAdd End If If (Me.onAddCompletedDelegate Is Nothing) Then Me.onAddCompletedDelegate = AddressOf Me.OnAddCompleted End If MyBase.InvokeAsync(Me.onBeginAddDelegate, New Object() {n1, n2}, Me.onEndAddDelegate, Me.onAddCompletedDelegate, userState) End Sub
与基于事件的异步调用方法一起使用且形式为
<operationName>``Completed
的操作完成事件。 例如:public event System.EventHandler<AddCompletedEventArgs> AddCompleted;
Public Event AddCompleted As System.EventHandler(Of AddCompletedEventArgs)
与基于事件的异步调用方法一起使用的每个操作的 System.EventArgs 类型(形式为
<operationName>``CompletedEventArgs
)。 例如:[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public partial class AddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { private object[] results; public AddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : base(exception, cancelled, userState) { this.results = results; } public double Result { get { base.RaiseExceptionIfNecessary(); return ((double)(this.results[0])); } } }
<System.Diagnostics.DebuggerStepThroughAttribute(), _ System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _ Partial Public Class AddCompletedEventArgs Inherits System.ComponentModel.AsyncCompletedEventArgs Private results() As Object Public Sub New(ByVal results() As Object, ByVal exception As System.Exception, ByVal cancelled As Boolean, ByVal userState As Object) MyBase.New(exception, cancelled, userState) Me.results = results End Sub Public ReadOnly Property Result() As Double Get MyBase.RaiseExceptionIfNecessary Return CType(Me.results(0),Double) End Get End Property End Class
在调用应用程序中,创建一个要在异步操作完成时调用的回调方法,如下面的示例代码所示。
// Asynchronous callbacks for displaying results. static void AddCallback(object sender, AddCompletedEventArgs e) { Console.WriteLine("Add Result: {0}", e.Result); }
' Asynchronous callbacks for displaying results. Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs) Console.WriteLine("Add Result: {0}", e.Result) End Sub
在调用操作之前,请使用类型为
<operationName>``EventArgs
的新通用 System.EventHandler<TEventArgs> 将处理程序方法(在上一步中创建)添加到<operationName>``Completed
事件。 然后调用<operationName>``Async
方法。 例如:// AddAsync double value1 = 100.00D; double value2 = 15.99D; client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback); client.AddAsync(value1, value2); Console.WriteLine("Add({0},{1})", value1, value2);
' AddAsync Dim value1 As Double = 100 Dim value2 As Double = 15.99 AddHandler client.AddCompleted, AddressOf AddCallback client.AddAsync(value1, value2) Console.WriteLine("Add({0},{1})", value1, value2)
示例
注意
基于事件的异步模型设计准则规定,如果返回了多个值,则一个值会作为 Result
属性返回,其他值会作为 EventArgs 对象上的属性返回。 因此产生的结果之一是,如果客户端使用基于事件的异步命令选项导入元数据,且该操作返回多个值,则默认的 EventArgs 对象返回一个值作为 Result
属性,返回的其余值是 EventArgs 对象的属性。如果要将消息对象作为 Result
属性来接收并要使返回的值作为该对象上的属性,请使用 /messageContract
命令选项。 这会生成一个签名,该签名会将响应消息作为 Result
对象上的 EventArgs 属性返回。 然后,所有内部返回值就都是响应消息对象的属性了。
using System;
namespace Microsoft.ServiceModel.Samples
{
// The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
class Client
{
static void Main()
{
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.");
Console.WriteLine();
// Create a client
CalculatorClient client = new CalculatorClient();
// AddAsync
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
Console.WriteLine("Add({0},{1})", value1, value2);
// SubtractAsync
value1 = 145.00D;
value2 = 76.54D;
client.SubtractCompleted += new EventHandler<SubtractCompletedEventArgs>(SubtractCallback);
client.SubtractAsync(value1, value2);
Console.WriteLine("Subtract({0},{1})", value1, value2);
// Multiply
value1 = 9.00D;
value2 = 81.25D;
double result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
// Divide
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();
}
// Asynchronous callbacks for displaying results.
static void AddCallback(object sender, AddCompletedEventArgs e)
{
Console.WriteLine("Add Result: {0}", e.Result);
}
static void SubtractCallback(object sender, SubtractCompletedEventArgs e)
{
Console.WriteLine("Subtract Result: {0}", e.Result);
}
}
}
Namespace Microsoft.ServiceModel.Samples
' The service contract is defined in generatedClient.vb, generated from the service by the svcutil tool.
Class Client
Public Shared Sub Main()
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.")
Console.WriteLine()
' Create a client
Dim client As New CalculatorClient()
' AddAsync
Dim value1 As Double = 100
Dim value2 As Double = 15.99
AddHandler client.AddCompleted, AddressOf AddCallback
client.AddAsync(value1, value2)
Console.WriteLine("Add({0},{1})", value1, value2)
' SubtractAsync
value1 = 145
value2 = 76.54
AddHandler client.SubtractCompleted, AddressOf SubtractCallback
client.SubtractAsync(value1, value2)
Console.WriteLine("Subtract({0},{1})", value1, value2)
' Multiply
value1 = 9
value2 = 81.25
Dim result As Double = client.Multiply(value1, value2)
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result)
' Divide
value1 = 22
value2 = 7
result = client.Divide(value1, value2)
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result)
Console.ReadLine()
'Closing the client gracefully closes the connection and cleans up resources
client.Close()
End Sub
' Asynchronous callbacks for displaying results.
Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs)
Console.WriteLine("Add Result: {0}", e.Result)
End Sub
Private Shared Sub SubtractCallback(ByVal sender As Object, ByVal e As SubtractCompletedEventArgs)
Console.WriteLine("Subtract Result: {0}", e.Result)
End Sub
End Class
End Namespace