【发布时间】:2011-01-21 17:16:17
【问题描述】:
是否有理由让每个 WCF 服务调用异步?
我正在和我的搭档讨论这个问题。他想让每个 WPF 服务调用异步以避免锁定 UI(它是桌面 WPF 应用程序)。我反对这个想法。我觉得在大多数情况下不需要 Async 调用,当需要时,RequestingClass 和 DataManager 都应该专门编码来处理 Async 调用。
我的论点是为所有内容设置回调的代码要多得多,而且非常令人困惑。我也认为这可能会导致性能下降,尽管我还没有验证这一点。他的论点是,有时您会获取大量数据并且它会锁定 UI,并且像这样设置 WCF 调用并没有太多工作(他也没有发现以下代码令人困惑)。
我们之前都从未使用过 WCF 服务器,所以我想我会给他一个怀疑的好处,并在这里征求一些其他意见。
例如:
我的方式:
public override User GetById(int id)
{
return new User(service.GetUserById(id));
}
它会锁定 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);
}
基类回调队列:
/// <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);
}
}
它不会锁定 UI、DataManager 或 WCF 服务通道,但是其中包含许多额外的编码。
无论如何,AsyncPatternWrapper 都在我们的应用程序中。它允许我们进行异步 WCF 调用并订阅回调事件
编辑 我们确实有一个包装器,我们可以从 UI 线程中使用它来包装任何 DataManager 调用。它在 BackgroundWorker 上执行 Synchronous 方法,并针对结果执行回调。
大部分额外代码是为了防止锁定 DataManager 和 WCF 服务通道。
【问题讨论】:
-
考虑评估新 C#“async/await”功能的 CTP 版本。它旨在使编写此类代码更加容易。我们很乐意在异步论坛上获得您的反馈。 msdn.microsoft.com/en-us/vstudio/async.aspx
-
@Eric:谢谢,我现在正在研究它,到目前为止我很喜欢它!
-
@Eric:你能告诉我关于将它与 WCF 服务一起使用的任何好的教程/演练吗?
标签: c# wcf asynchronous