|
异步调用的匹配客户端代码将类似于如下所示:
CalculatorClient proxy = new CalculatorClient(); int sum; AsyncCallback completion = (result)=> { sum = proxy.EndAdd(result); Debug.Assert(sum == 5); proxy.Close(); }; proxy.BeginAdd(2,3,completion,null);
|
虽然您可以按原样使用这些方法,但是提供给 Begin 的完成回调是从线程池中的线程调用的。如果使用回调访问某些与特定线程相关联的资源,则这样做会出现严重问题。Windows 窗体(或 WPF)应用程序即为典型示例,此应用程序异步调度较长的服务调用(避免阻止 UI),然后希望使用调用结果来更新 UI。不允许使用原始 Begin 进行更新,因为只允许 UI 线程更新 UI。为了更好地处理此情况,已用受保护的 InvokeAsync 方法扩展了 ClientBase 基类,该方法可以获取客户端的同步上下文并将其用于调用完成回调,如图 10 所示。
Figure 10:ClientBase 中的异步回调管理
public abstract class ClientBase : ... { protected delegate IAsyncResult BeginOperationDelegate( object[] inValues,AsyncCallback asyncCallback,object state); protected delegate object[] EndOperationDelegate(IAsyncResult result);
//Picks up sync context used for completion callback protected void InvokeAsync(BeginOperationDelegate beginOpDelegate, object[] inValues, EndOperationDelegate endOpDelegate, SendOrPostCallback opCompletedCallback, object userState) {} //More members }
|
ClientBase 还提供了一个事件参数帮助器类和两个用于启动和结束异步调用的专用委托。生成的代理类由 ClientBase 派生而来,此代理类将使用这些基本功能。代理将具有一个 Completed 公共事件(该事件使用特定于异步方法结果的强类型事件参数类)和两个 Async 方法(用于异步调度调用):
partial class AddCompletedEventArgs : AsyncCompletedEventArgs { public int Result {get;} } class CalculatorClient : ClientBase,ICalculator { public event EventHandler AddCompleted; public void AddAsync(int number1,int number2,object userState); public void AddAsync(int number1,int number2); //Rest of the proxy }
|
客户端还可以为 Completed 事件订阅事件处理程序,以便在完成时调用此事件处理程序。使用 Async 与 Begin 的主要差别在于:Async 方法获取客户端的同步上下文,并在该同步上下文中激发 Completed 事件,如图 11 所示。
Figure 11:针对用户界面友好的异步调用的调用
partial class CalculatorForm : Form { CalculatorClient m_Proxy;
public MyClient() { InitializeComponent(); m_Proxy = new CalculatorClient(); m_Proxy.AddCompleted += OnAddCompleted; } void CallAsync(object sender,EventArgs args) { m_Proxy.AddAsync(2,3); //Sync context picked up here } //Called on the UI thread void OnAddCompleted(object sender,AddCompletedEventArgs args) { Text = "Sum = " + args.Result; } }
|
通过“Collection”(集合)类型组合框,您可以指定如何向客户端显示在服务元数据中找到的某些类型的集合和数组。例如,如果服务操作返回 IEnumerable、IList 或 ICollection 集合中的某一个,则默认情况下代理会将其显示为数组。例如,以下服务端操作:
[OperationContract] IEnumerable GetNumbers(); |
将在代理上表示为:
[OperationContract] int[] GetNumbers(); |
但是,您可以请求 Visual Studio 2008 使用其他集合(例如用于进行数据绑定的 BindingList、List、Collection 和 LinkedList 等)。如果可以进行转换,代理将使用请求的集合类型而不是数组,如下所示:
[OperationContract] List GetNumbers(); |
字典也具有类似功能。通常情况下,如果服务操作返回可序列化的字典,如下所示:
[Serializable] class MyDictionary : IDictionary {...} [OperationContract] MyDictionary GetDictionary();
|
|