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

时间:2011-07-26 11:42:24

标签: 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)调用异步的线程无法阻塞,因为异步永远不会被调用。实际上,如果你把那个线程放到一个等待循环中,我就注意到它也没有被调用 2)您需要一种方法来从已完成的异步调用方法发出信号。

很抱歉这太久了,谢谢你的阅读。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我使用了一个我自己构建的类来执行同步的加载操作。使用该类,您可以注册不同的domaincontexts的多个加载操作,然后逐个执行它们。当所有操作完成(成功或失败)时,您可以向被调用的类的构造函数提供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服务,所以也许这个课程对你没用。

答案 1 :(得分:0)

有一些选择:

- 您可以通过检查它的实现或仅使用它而不是纯粹的wcf来查看Agatha-rrsl。该框架允许您对请求进行排队。您可以阅读更多here

- 另一种选择是使用Reactive扩展。有一个SO示例here以及更多信息herehere

- 您可以尝试Jeffrey Richter的Power Thread库。他通过C#在他的书CLR上描述了这一点。您可以找到图书馆here。这个webcast会为您提供一些相关信息。

- 您可以随时推出自己的实施。屈服声明在这里是一个很好的帮助。错误处理使得解决方案变得非常困难。