multithreading - Silverlight - 一次将应用程序限制为一个 WCF 调用

标签 multithreading silverlight wcf asynchronous

Silverlight 一次只能同时发送一定数量的 WCF 请求。我正在尝试序列化我的应用程序的特定部分正在执行的请求,因为我不需要它们同时运行。

问题如下(总结如下):
“Silverlight 应用程序中的 WCF 代理使用启动 Web 服务调用的线程的 SynchronizationContext 来安排在收到响应时调用异步事件处理程序。当从 Silverlight 应用程序的 UI 线程启动 Web 服务调用时,异步事件处理程序代码也将在 UI 线程上执行。”
http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html

摘要:基本上,如果您阻塞调用异步方法的线程,它将永远不会被调用。

我无法找出正确的线程模型,这将以合理的方式给我想要的东西。

我唯一的其他要求是我不希望 UI 线程阻塞。

据我所见,如果 UI 线程有一个工作线程将调用排队为 Action,那么应该怎么做?代表,然后使用 AutoResetEvent在另一个工作线程中一次执行一个任务。有两个问题:
1)调用 async 的线程不能阻塞,因为那样 async 永远不会被调用。实际上,如果您将该线程放入等待循环中,我注意到它也不会被调用
2)您需要一种方法来从异步调用的完成方法发出信号,表明它已完成。

抱歉说了这么久,感谢阅读。有任何想法吗?

最佳答案

我使用了一个我自己构建的类来同步执行加载操作。使用该类,您可以注册不同域上下文的多个加载操作,然后一一执行。当所有操作完成(成功或失败)时,您可以向被调用的类的构造函数提供一个 Action。

这是类的代码。我认为它不完整,您必须对其进行更改以符合您的期望。也许它可以在你的情况下帮助你。

  public class DomainContextQueryLoader {
    private List<LoadOperation> _failedOperations;
    private Action<DomainContextQueryLoader> _completeAction;
    private List<QueuedQuery> _pendingQueries = new List<QueuedQuery>();

    public DomainContextQueryLoader(Action<DomainContextQueryLoader> completeAction) {
        if (completeAction == null) {
            throw new ArgumentNullException("completeAction", "completeAction is null.");
        }
        this._completeAction = completeAction;
    }

    /// <summary>
    /// Expose the count of failed operations
    /// </summary>
    public int FailedOperationCount {
        get {
            if (_failedOperations == null) {
                return 0;
            }
            return _failedOperations.Count;
        }
    }

    /// <summary>
    /// Expose an enumerator for all of the failed operations
    /// </summary>
    public IList<LoadOperation> FailedOperations {
        get {
            if (_failedOperations == null) {
                _failedOperations = new List<LoadOperation>();
            }
            return _failedOperations;
        }
    }

    public IEnumerable<QueuedQuery> QueuedQueries {
        get {
            return _pendingQueries;
        }
    }

    public bool IsExecuting {
        get;
        private set;
    }

    public void EnqueueQuery<T>(DomainContext context, EntityQuery<T> query) where T : Entity {
        if (IsExecuting) {
            throw new InvalidOperationException("Query cannot be queued, cause execution of queries is in progress");
        }
        var loadBatch = new QueuedQuery() {
            Callback = null,
            Context = context,
            Query = query,
            LoadOption = LoadBehavior.KeepCurrent,
            UserState = null
        };

        _pendingQueries.Add(loadBatch);
    }

    public void ExecuteQueries() {
        if (IsExecuting) {
            throw new InvalidOperationException("Executing of queries is in progress");
        }

        if (_pendingQueries.Count == 0) {
            throw new InvalidOperationException("No queries are queued to execute");
        }

        IsExecuting = true;
        var query = DequeueQuery();
        ExecuteQuery(query);
    }

    private void ExecuteQuery(QueuedQuery query) {
        System.Diagnostics.Debug.WriteLine("Load data {0}", query.Query.EntityType);
        var loadOperation = query.Load();
        loadOperation.Completed += new EventHandler(OnOperationCompleted);
    }

    private QueuedQuery DequeueQuery() {
        var query = _pendingQueries[0];
        _pendingQueries.RemoveAt(0);
        return query;
    }

    private void OnOperationCompleted(object sender, EventArgs e) {
        LoadOperation loadOperation = sender as LoadOperation;
        loadOperation.Completed -= new EventHandler(OnOperationCompleted);

        if (loadOperation.HasError) {
            FailedOperations.Add(loadOperation);
        }

        if (_pendingQueries.Count > 0) {
            var query = DequeueQuery();
            ExecuteQuery(query);
        }
        else {
            IsExecuting = false;
            System.Diagnostics.Debug.WriteLine("All data loaded");
            if (_completeAction != null) {
                _completeAction(this);
                _completeAction = null;
            }
        }
    }

}

更新:
我刚刚注意到您没有使用 WCF RIA 服务,所以这门课可能对您没有帮助。

关于multithreading - Silverlight - 一次将应用程序限制为一个 WCF 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6829461/

相关文章:

java - 如何避免显示“应用程序无响应”对话框

silverlight - 为什么 Entity Framework 在应该更新的时候却插入了?

silverlight - 是否可以在 Silverlight 网络应用程序和 Windows Phone 7 应用程序之间共享代码

c# - 我可以强制 svcutil.exe 为 WCF 服务生成数据协定吗?

c# - Dispatcher.Invoke 和线程访问的问题

java - Multitheard的应用程序看起来可以随机运行

java - 多线程类加载可能吗?

silverlight - 在 Silverlight 中创建报告(以 PDF 格式或将其发送到打印机)

.net - 什么决定了 WCF 测试客户端中方法的顺序?

javascript - 验证来自 Javascript 的跨域请求