繁体   English   中英

WPF / WCF异步服务调用和SynchronizationContext

[英]WPF/WCF Async Service Call and SynchronizationContext

我觉得有比我想出的更好的解决方案了。 这是问题所在:

WPF表单将调用WCF方法,该方法返回布尔值。 调用本身不应位于U​​I线程上,并且调用结果将需要显示在表单上,​​因此应将返回结果编组回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/awaitasync/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 SynchronizationContextTaskSchedulerChatServiceGateway强制回调/继续在正确的线程上执行,但它会使您的实现ChatServiceGateway就个人而言(这只是我的观点 ),我会说这有点代码味道。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM