是否有理由让每个WCF调用异步?

Rac*_*hel 8 c# wcf asynchronous

是否有理由让每个WCF服务调用异步?

我和我的伙伴正在讨论这个问题.他想让每个WPF服务调用Async以避免锁定UI(它是桌面WPF应用程序).我反对这个想法.在大多数情况下,我不认为需要异步调用,并且在需要时,应该专门编码RequestingClass和DataManager来处理异步调用.

我的论点是,为所有事情设置回调的代码要多得多,而且非常令人困惑.我也认为这可能会导致性能下降,尽管我尚未对此进行验证.他的论点是,有时候你会收到大量数据并且会锁定用户界面,并且设置这样的WCF调用并不是那么多工作(他也没有发现下面的代码令人困惑).

我们之前从未使用过WCF服务器,所以我想我会给他带来疑问,并在这里询问其他一些意见.

例如:

我的方式:

public override User GetById(int id)
{
    return new User(service.GetUserById(id));
}
Run Code Online (Sandbox Code Playgroud)

它锁定UI,UserDataManager和WCF服务通道,直到WCF服务器返回User DataTransferObject,但它易于理解并快速编码.它将用于大多数WCF服务调用,除非它实际上预期获取数据的延迟,在这种情况下DataManager将被设置为处理异步调用.

他的方法:

public override void GetById(int id, Action<UserGroup> callback = null)
{
    // This is a queue of all callbacks waiting for a GetById request
    if (AddToSelectbyIdQueue(id, callback))
        return;

    // Setup Async Call
    var wrapper = new AsyncPatternWrapper<UserDTO>(
        (cb, asyncState) => server.BeginGetUserById(id, cb, asyncState),
        Global.Instance.Server.EndGetUserById);

    // Hookup Callback
    wrapper.ObserveOnDispatcher().Subscribe(GetByIdCompleted);

    // Run Async Call
    wrapper.Invoke();
}

private void GetByIdCompleted(UserDTO dto)
{
    User user = new User(dto);

    // This goes through the queue of callbacks waiting 
    // for this method to complete and executes them
    RunSelectIdCallbacks(user.UserId, user);
}
Run Code Online (Sandbox Code Playgroud)

基类的回调队列:

/// <summary>
/// Adds an item to the select queue, or a current fetch if there is one
/// </summary>
/// <param name="id">unique object identifier</param>
/// <param name="callback">callback to run</param>
/// <returns>False if it needs to be fetched, True if it is already being
/// fetched</returns>
protected virtual bool AddToSelectbyIdQueue(int id, Action<T> callback)
{
    // If the id already exists we have a fetch function already going
    if (_selectIdCallbacks.ContainsKey(id))
    {
        if(callback != null)
            _selectIdCallbacks[id].Add(callback);
        return true;
    }

    if (callback != null)
    {
        List<Action<T>> callbacks = new List<Action<T>> {callback};
        _selectIdCallbacks.Add(id, callbacks);
    }

    return false;
}

/// <summary>
/// Executes callbacks meant for that object Id and removes them from the queue
/// </summary>
/// <param name="id">unique identifier</param>
/// <param name="data">Data for the callbacks</param>
protected virtual void RunSelectIdCallbacks(int id, T data)
{
    if (_selectIdCallbacks.ContainsKey(id))
    {
        foreach (Action<T> callback in _selectIdCallbacks[id])
            callback(data);

        _selectIdCallbacks.Remove(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

它不会锁定UI,DataManager或WCF服务通道,但是会有很多额外的编码.

无论如何,AsyncPatternWrapper都在我们的应用程序中.它允许我们进行异步WCF调用并订阅回调事件

编辑 我们有一个包装器,我们可以从UI线程中使用它来包装任何DataManager调用.它在BackgroundWorker上执行Synchronous方法,并对结果执行回调.

大多数额外代码是为了防止锁定DataManager和WCF服务通道.

SLa*_*aks 5

你的伴侣是对的; 你不应该阻止UI线程.

作为异步调用的替代方法,您还可以使用BackgroundWorker或ThreadPool在后台线程中进行同步调用.