Silverlight - ограничить приложение одним вызовом WCF за раз - PullRequest
3 голосов
/ 26 июля 2011

Silverlight может отправлять только определенное количество одновременных запросов WCF одновременно. Я пытаюсь сериализовать запросы, которые выполняет определенный раздел моего приложения, потому что мне не нужно, чтобы они выполнялись одновременно.

Проблема заключается в следующем (резюме ниже): «Прокси-серверы WCF в приложениях Silverlight используют SynchronizationContext потока, из которого инициируется вызов веб-службы, для планирования вызова асинхронного обработчика событий при получении ответа. Когда вызов веб-службы инициируется из потока пользовательского интерфейса приложения Silverlight , код обработчика асинхронных событий также будет выполняться в потоке пользовательского интерфейса. " http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html

итоги: в основном, если вы заблокируете поток, вызывающий асинхронный метод, он никогда не будет вызван.

Я не могу понять правильную модель работы с нитями, которая дала бы мне то, что я хочу разумным образом.

Мое единственное другое требование - я не хочу, чтобы поток пользовательского интерфейса блокировал.

Насколько я вижу, должен работать, если поток пользовательского интерфейса имеет рабочий поток, который ставит в очередь вызовы как делегаты Action, а затем использует AutoResetEvent для выполнения задачи. за один раз в другом рабочем потоке. Есть две проблемы: 1) Поток, который вызывает async, не может заблокировать, потому что тогда async никогда не будет вызван. На самом деле, если вы поместите этот поток в цикл ожидания, я заметил, что он тоже не вызывается 2) Вам нужен способ сообщить из завершенного метода асинхронного вызова, что это сделано.

Извините, что так долго, спасибо, что прочитали. Есть идеи?

Ответы [ 2 ]

1 голос
/ 27 июля 2011

Я использовал класс, который я строю самостоятельно для синхронного выполнения операций загрузки. С помощью класса вы можете зарегистрировать несколько операций загрузки различных доменных контекста, а затем выполнить их одну за другой. Вы можете предоставить 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 Services, поэтому, возможно, этот класс вам не поможет.

0 голосов
/ 27 июля 2011

Есть несколько вариантов:

- Вы можете взглянуть на Agatha-rrsl, либо ознакомившись с его реализацией, либо просто используя его вместо чистого wcf. Каркас позволяет ставить запросы в очередь. Вы можете прочитать больше здесь . - Другой вариант - использовать реактивное расширение. Вот пример SO здесь и более подробная информация здесь и здесь . - Вы можете попробовать библиотеку Power Thread от Джеффри Рихтера. Он описывает это в своей книге CLR через C #. Вы можете найти библиотеку здесь . Эта трансляция дает вам некоторую информацию об этом. - Вы всегда можете свернуть собственную реализацию. Здесь очень полезна инструкция по выходу. Обработка ошибок делает очень трудным правильное решение.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...