[英]WPF/WCF Async Service Call and SynchronizationContext
我觉得有比我想出的更好的解决方案了。 这是问题所在:
WPF表单将调用WCF方法,该方法返回布尔值。 调用本身不应位于UI线程上,并且调用结果将需要显示在表单上,因此应将返回结果编组回UI线程。
在此示例中,我创建了一个“ ServiceGateway”类,该表单将向其传递一个方法,该方法将在完成Login操作后执行。 网关应该使用UI SynchronizationContext调用此登录完成的委托,该委托在网关从窗体实例化时传递。 Login方法使用anon调用_proxy.Login的调用。 异步委托,然后提供一个回调,该回调使用UI SynchronizationContext调用提供给网关的委托(“回调”参数)(从窗体):
[CallbackBehavior(UseSynchronizationContext = false)]
public class ChatServiceGateway : MessagingServiceCallback
{
private MessagingServiceClient _proxy;
private SynchronizationContext _uiSyncContext;
public ChatServiceGateway(SynchronizationContext UISyncContext)
{
_proxy = new MessagingServiceClient(new InstanceContext(this));
_proxy.Open();
_uiSyncContext = UISyncContext;
}
public void Login(String UserName, Action<bool> callback)
{
new Func<bool>(() => _proxy.Login(UserName)).BeginInvoke(delegate(IAsyncResult result)
{
bool LoginResult = ((Func<bool>)((AsyncResult)result).AsyncDelegate).EndInvoke(result);
_uiSyncContext.Send(new SendOrPostCallback(obj => callback(LoginResult)), null);
}, null);
}
响应按钮单击事件,从表单中调用Login方法。
这可以正常工作,但是我怀疑我要以错误的方式使用Login方法。 尤其是因为我必须对WCF服务的其他任何方法调用做同样的事情,而且这样做很丑陋。
我想将异步行为和ui同步封装在网关中。 在WCF端实现异步行为会更好吗? 基本上,我很感兴趣是否可以为其他方法更通用地实现上述代码,或者是否有更好的方法。
只要您的目标至少是VS 2012和.NET 4.5, async/await
是async/await
的方法。 请注意,缺少SynchronizationContext
参考-在await
之前将其捕获,并在异步操作完成后重新发布。
public async Task Login(string userName, Action<bool> callback)
{
// The delegate passed to `Task.Run` is executed on a ThreadPool thread.
bool loginResult = await Task.Run(() => _proxy.Login(userName));
// OR
// await _proxy.LoginAsync(UserName);
// if you have an async WCF contract.
// The callback is executed on the thread which called Login.
callback(loginResult);
}
Task.Run
主要用于将与CPU绑定的工作推送到线程池,因此上面的示例确实滥用了它,但是如果您不想重写MessagingServiceClient
实现的协定以使用基于Task
的异步方法,则可以仍然是一个不错的选择。
或.NET 4.0方式(不支持async/await
):
public Task Login(string userName, Action<bool> callback)
{
// The delegate passed to `Task.Factory.StartNew`
// is executed on a ThreadPool thread.
var task = Task.Factory.StartNew(() => _proxy.Login(userName));
// The callback is executed on the thread which called Login.
var continuation = task.ContinueWith(
t => callback(t.Result),
TaskScheduler.FromCurrentSynchronizationContext()
);
return continuation;
}
这与您当前的处理方式有所不同, 因为调用者有责任确保希望在其上执行回调的情况下在UI线程上调用 Login
。 但是,这是async
标准做法,尽管您可以在ChatServiceGateway
保留对UI SynchronizationContext
或TaskScheduler
的ChatServiceGateway
以强制回调/继续在正确的线程上执行,但它会使您的实现ChatServiceGateway
就个人而言(这只是我的观点 ),我会说这有点代码味道。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.