Есть ли событие, чтобы сообщить, когда автоматически созданный прокси WCF выполняет асинхронную операцию? - PullRequest
0 голосов
/ 20 января 2010

Я создаю приложение Silverlight, и у меня есть несколько проблем с автоматически сгенерированным прокси (переходя на ссылку добавления службы в Visual Studio 2008)

Когда прокси создается на клиенте, асинхронные методыгенерируется, и я могу их вызывать, и это нормально.

Но то, что я действительно хотел бы сделать, это иметь анимацию «занят» или «асинхронная загрузка» на моей странице.Я достиг этого в прошлом, имея статический класс, который хранит количество асинхронных вызовов, выполняемых в настоящее время. Проблема с этим подходом заключается в том, что я должен был помнить, что нужно вручную увеличивать и уменьшать счетчик всякий раз, когда я вызываю асинхронный метод впрокси (и уменьшите его, когда он будет завершен) - и, конечно, я бы забыл делать это довольно часто.

Другой подход, который я попробовал, который был немного лучше, заключался в том, чтобы обернуть прокси в мой собственный класс-обертку.поэтому вместо вызова методов на прокси я вызову методы на оболочке, а оболочка будет увеличивать / уменьшать счетчик - это было немного лучше, но это оказалось немного болезненным, когда операция сжимается / имена / параметрымой сервис постоянно менялся ESP.когда служба находилась на ранней стадии разработки.

Я что-то упустил?Потому что я действительно думаю, что это должно быть немного проще, чем мой нынешний подход.

Ответы [ 2 ]

0 голосов
/ 18 марта 2011

Я только недавно создал подход, который решает эту проблему См .: Метод динамического IL вызывает «Операция может дестабилизировать время выполнения»

По сути, создайте оболочку для вызова вашего асинхронного метода и позвольте этой оболочке зарегистрировать событие общего назначения, используя динамические методы и отражение. Тогда вам не нужно беспокоиться о поддержке оболочки для каждого асинхронного вызова в вашей оболочке.

0 голосов
/ 20 января 2010

Согласен, должно быть что-то проще, чем ваш нынешний подход. Но до тех пор, пока мы не сможем использовать шаблоны T4 для генерации прокси-классов или пока вы не захотите свернуть свои собственные (не рекомендуется IMO, YMMV), я думаю, что то, что вы уже попробовали, - ваш лучший шанс.

В настоящее время я использую гибрид обоих подходов. Я обернул все вызовы WCF в серию классов доступа к данным, которые переводят не очень полезную модель, управляемую событиями, которую предоставляет MS, в гораздо более простой подход обратного вызова. Внутри этих классов доступа к данным я также обернул каждый вызов статическим методом PreProcessCall (), который обрабатывает увеличение счетчика ожидающих вызовов и маршалинг вызова в фоновый поток; и я обернул каждый обратный вызов статическим методом PostProcessCall (), который уменьшает счетчик ожидающих вызовов и маршалирует обратный вызов в потоке пользовательского интерфейса.

    public static void PreProcessCall(Action action)
    {
        Logger.LogDebugMessage("Pre-processing call for {0}", (new StackTrace()).GetFrame(1).GetMethod().Name);
        Interlocked.Increment(ref pendingCalls);
        ThreadPool.QueueUserWorkItem(o =>
            {
                try
                {
                    action();
                }
                catch (System.Exception ex)
                {
                    DataPublisher.GetPublisher().RaiseDataProcessExceptionOccurred(ex, ex.Message);
                    UpdatePendingCalls();
                }
            });
    }

    private static void UpdatePendingCalls()
    {
        Interlocked.Decrement(ref pendingCalls);
        Debug.Assert(pendingCalls >= 0, "The number of pending calls should never go below zero.");
        if (pendingCalls <= 0)
        {
            lock (pendingCallNotifications)
            {
                while (pendingCallNotifications.Count > 0)
                {
                    Action callback = pendingCallNotifications.Dequeue();
                    Globals.Dispatcher.BeginInvoke(callback);
                }
            }
        }
    }

    public static void PostProcessCall(Action action)
    {
        Logger.LogDebugMessage("Post-processing call for {0}", (new StackTrace()).GetFrame(1).GetMethod().Name);
        UpdatePendingCalls();
        Globals.Dispatcher.BeginInvoke(() =>
            {
                try
                {
                    action();
                }
                catch (System.Exception ex)
                {
                    DataPublisher.GetPublisher().RaiseDataProcessExceptionOccurred(ex, ex.Message);
                }
            });
    }

Таким образом, типичный вызов выглядит примерно так:

    public void SendMessage(string message, OperationCallback callback)
    {
        DataConnectionManager.PreProcessCall(() =>
            {
                Logger.LogDebugMessage("SendChatMessage");
                notificationClient.SendChatMessageAsync(roomViewModel.SessionId, message, callback);
            });
    }

    void RoomService_SendChatMessageCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
    {
        OperationCallback callback = (OperationCallback)e.UserState;
        DataConnectionManager.PostProcessCall(() =>
            {
                if (callback != null)
                {
                    callback(e.Error);
                }
                Logger.LogDebugMessage("SendChatMessageCompleted.");
            });
    }

Как я уже сказал, в основном то, что вы уже пробовали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...