Вызов веб-службы синхронно из приложения Silverlight 3? - PullRequest
1 голос
/ 28 мая 2010

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

К сожалению, код веб-службы, сгенерированный в Silverlight, производит только асинхронные методы, поэтому мне было интересно, есть ли у кого-нибудь работающий код, которому удалось обойти это?

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

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

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

Или что-то в этом роде.

Вот моя собственная версия, которую я написал до того, как нашел вышеуказанный рецепт, но она страдает от той же проблемы:

public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
    string securityToken = "DUMMYTOKEN";
    string input = "DUMMYINPUT";
    object result = null;
    Exception resultException = null;
    object evtLock = new object();

    var evt = new System.Threading.ManualResetEvent(false);
    try
    {
        var client = new MinGatServices.DataAccessLayerServiceSoapClient();
        client.ExecuteRequestCompleted += (s, e) =>
        {
            resultException = e.Error;
            result = e.Result;
            lock (evtLock)
            {
                if (evt != null)
                    evt.Set();
            }
        };
        client.ExecuteRequestAsync(securityToken, input);
        try
        {
            var didComplete = evt.WaitOne(10000);
            if (!didComplete)
                throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
        }
        finally
        {
            client.CloseAsync();
        }
    }
    finally
    {
        lock (evtLock)
        {
            evt.Close();
            evt = null;
        }
    }

    if (resultException != null)
        throw resultException;
    else
        return result;
}

По сути, оба рецепта делают это:

  • Настройка ManualResetEvent
  • Подключиться к завершенному событию
  • Обработчик событий получает результат от сервисного вызова и сигнализирует о событии
  • Основной поток теперь запускает вызов веб-службы асинхронно
  • Затем он ожидает события, чтобы стать сигнальным

Однако обработчик событий не вызывается до тех пор, пока не будет возвращен указанный выше метод, поэтому мой код проверяет наличие evt != null и т. Д., Чтобы исключить TargetInvocationException от уничтожения моей программы после истечения времени ожидания метода.

Кто-нибудь знает:

  • ... если это вообще возможно в Silverlight 3
  • ... что я не так сделал выше?

1 Ответ

1 голос
/ 28 мая 2010

Я подозреваю, что вещь MinGatServices пытается помочь, гарантируя, что ExecuteRequestCompleted отправляется в основной поток пользовательского интерфейса.

Я также подозреваю, что ваш код уже выполняется в главном потоке пользовательского интерфейса, который вы заблокировали. Никогда не блокируйте поток пользовательского интерфейса в Silverlight, если вам нужно заблокировать пользовательский интерфейс, используйте что-то вроде BusyIndicator control.

Ответ коленного рефлекса - «асинхронный код», но он не удовлетворяет требованию вашего вопроса.

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

Конечно, MinGatServices может гарантировать, что обратный вызов происходит в том же потоке, который выполнил ExecuteRequestAsync, и в этом случае вам нужно будет запустить его в другом потоке (возврат к потоку пользовательского интерфейса будет приемлемым ): -

 Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...