异步

此异步示例演示客户端如何以异步方式访问服务操作,以及服务如何以异步方式实现其操作。此示例基于实现计算器服务的入门示例。是使用同步调用还是异步调用只是一个本地决策,而不会影响在网络上发送的消息。尽管服务实现了一些同步操作,但是客户端仍能够以异步方式访问服务操作。尽管客户端以同步方式调用服务,但是服务仍能够以异步方式实现某些操作。

ms751505.note(zh-cn,VS.100).gif注意:
本主题的最后介绍了此示例的设置过程和生成说明。

在此示例中,客户端是一个控制台应用程序 (.exe),而且服务自承载在控制台应用程序 (.exe) 中。

服务实现 ICalculator 接口。客户端可以在该接口上以异步方式调用操作,这意味着 Add 之类的操作现在具有 BeginAddEndAdd

ms751505.note(zh-cn,VS.100).gif注意:
有关异步模式的更多详细信息,请参见 .NET Framework 文档。

客户端已经生成了支持这些异步操作的代码。客户端是通过运行带 /a (async) 命令选项的ServiceModel 元数据实用工具 (Svcutil.exe) 工具来创建的,如下所示:

svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples https://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35

Add 操作的服务协定的客户端异步版本看上去类似于下面的代码。

[System.ServiceModel.ServiceContractAttribute(Namespace=
                   "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [System.ServiceModel.OperationContractAttribute(
       AsyncPattern=true)]
    System.IAsyncResult BeginAdd(double n1, double n2, 
                   System.AsyncCallback callback, object asyncState);
    double EndAdd(System.IAsyncResult result);
    
    ...
}

当同时指定 /tcv:Version35 选项和 /async 选项时,所生成的客户端类型将实现用来调用服务且基于事件的异步模式。有关信息,请参见基于事件的异步模式概述(可能为英文网页)。若要以异步方式访问服务操作,应用程序需要在客户端上向 [Operation]Completed 事件添加事件处理程序,然后调用 [Operation]Async 方法(例如,AddAsync),如下面的示例代码中所示。

// Create a client.
CalculatorClient client = new CalculatorClient();

// BeginAdd.
double value1 = 100.00D;
double value2 = 15.99D;

client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);

在该示例中,客户端以异步方式启动两个操作:AddSubtract

在执行回调函数时,客户端会访问 [Operation]CompletedEventArgs 输入参数上的 Result 属性以检索结果。

static void AddCallback(object sender, AddCompletedEventArgs e)
{
 Console.WriteLine("Add Result: {0}", e.Result);
}

所有的异步行为都发生在客户端本地,而且不会影响客户端发出消息的方式或服务处理消息的方式。在用户界面 (UI) 应用程序中使用此模式的通常原因是为了释放 UI 线程以便更新屏幕。当服务充当客户端,而且您希望消息处理线程不再调用其他服务时,此模式也适用。下一节将演示如何将服务操作设置为异步操作。

服务实现 ICalculator 接口,如下面的代码中所示。

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [OperationContract]
    double Add(double n1, double n2);
    
    [OperationContract]
    double Subtract(double n1, double n2);
    
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginMultiply(double n1, double n2,
        AsyncCallback callback, object state);
    double EndMultiply(IAsyncResult ar);

    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginDivide(double n1, double n2, 
        AsyncCallback callback, object state);
    double EndDivide(IAsyncResult ar); 
}

该协定的前两个操作由 Windows Communication Foundation (WCF) 运行库以同步方式调用。最后两对操作用来以异步方式调用服务。此示例将 AsyncPattern 属性设置为 true。此属性设置与 .NET Framework 异步模式的实现一起,通知运行库以异步方式调用该操作。

在服务实现中使用此模式的原因在于,在执行需要花费大量时间的输入和输出操作(如访问磁盘、访问数据库或调用另一个服务)时,通常需要释放消息处理线程。此示例演示如何用 IAsyncResult 的实现来包装文件的输入和输出操作。在编写自己的 IAsyncResult 实现时,可以重用 MathAsyncResult 类的实现的基类。

ms751505.note(zh-cn,VS.100).gif注意:
此示例使用 PerCallMultiple 来防止出现会话绑定随附的排序行为。默认情况下,wsHttpBinding 使用会话来建立安全上下文。这不会影响客户端或服务上消息处理的异步性质,但是它会将重点放在对响应的计时上,而且会允许客户端遵循并发(而不是依次)回调。

运行示例时,操作的请求和响应将显示在客户端控制台窗口中。AddSubtract 请求不会阻止,因为它们是以异步方式调用的。之后,MultiplyDivide 运算将阻止,它们的结果将在请求发出的同时显示出来。最后,当这些结果返回到客户端时,AddSubtract 运算的结果将显示出来。sleep 在服务的 AddSubtract 实现中用来显示客户端上的异步回调。

Add(100,15.99)
Subtract(145,76.54)
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714
Add Result: 115.99
Subtract Result: 68.46

线程 ID 在服务上用来演示同步调用(如 AddSubtract)是在单个线程上处理的。异步调用(如 MultiplyDivide)会涉及多个线程。服务的输出看上去如下所示。

Received Add Synchronously on ThreadID 11:  Sleeping for 3 seconds
Asynchronous call: BeginMultiply on ThreadID 12
Received Subtract Synchronously on ThreadID 12:  Sleeping for 3 seconds
IO thread for * operation on ThreadID 13
EndMultiply called on ThreadID 14
Asynchronous call: BeginDivide on ThreadID 14
IO thread for / operation on ThreadID 13
EndDivide called on ThreadID 14
Returning Add Result on ThreadID 11
Returning Subtract Result on ThreadID 12

.NET Framework 异步模式可以在客户端和/或服务上使用。如该示例中所示,这两端是相互独立的。

设置、生成和运行示例

  1. 请确保已经执行了 Windows Communication Foundation 示例的一次性安装过程

  2. 若要生成 C# 或 Visual Basic .NET 版本的解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。

  3. 若要用单机配置或跨计算机配置来运行示例,请按照Running the Windows Communication Foundation Samples中的说明进行操作。

ms751505.Important(zh-cn,VS.100).gif 注意:
您的计算机上可能已安装这些示例。在继续操作之前,请先检查以下(默认)目录。

<安装驱动器>:\WF_WCF_Samples

如果此目录不存在,请访问针对 .NET Framework 4 的 Windows Communication Foundation (WCF) 和 Windows Workflow Foundation (WF) 示例(可能为英文网页),下载所有 Windows Communication Foundation (WCF) 和 WF 示例。此示例位于以下目录。

<安装驱动器>:\WF_WCF_Samples\WCF\Basic\Contract\Service\Asynchronous