1

Анализ файлов журналов Я заметил, что ~ 1% вызовов службы заканчивается с TimeoutException на стороне клиента Silverlight. Услуги (wcf) довольно просты и не выполняют длинных вычислений. Согласно журналу, все вызовы служб всегда обрабатываются менее чем за 1 секунду (даже если на клиенте происходит событие TimeoutException!), Поэтому это не время ожидания сервера.TimeoutException при одновременных вызовах служб WCF из приложения Silverlight

Итак, что не так? Может быть, это проблема конфигурации или сети? Как я могу избежать этого? Какая дополнительная информация о регистрации может быть полезна для локализации этой проблемы?

Единственным обходным решением, которое я придумал, является повторный вызов службы после таймаута.

Буду признателен за любую помощь по этой проблеме!

Обновление: При запуске приложение выполняет 17 служебных вызовов и 12 из них одновременно (может это быть причиной отказа?).

Обновление: Журнал WCF не содержит полезной информации об этой проблеме. Кажется, что некоторые служебные вызовы не доходят до серверной части.

+0

У меня здесь путаница. Как вы использовали ClientBaseExtender? Получается ли ваш прокси-сервер от ClientBaseExtender? Но прокси-класс уже получен из System.ServiceModel.ClientBase. Итак, как вы подключаете ClientBaseExtender с MyServiceClient? –

+0

Нет, ClientBaseExtender предоставляет метод расширения (http://msdn.microsoft.com/en-us/library/bb383977.aspx) для ClientBase. Таким образом, вы можете использовать этот метод в любых наследователях ClientBase. –

+0

Какие файлы журнала ** вы анализируете? с любым _tool_? – Kiquenet

ответ

6

Проблема заключается в максимальном количестве одновременных подключений к одному серверу в Internet Explorer 7/6. Это всего 2! http://msdn.microsoft.com/en-us/library/cc304129(VS.85).aspx

Если у нас есть 3 (напр.) Одновременные вызовы службы, два из них будут немедленно отправлены на сервер, а третья будет ждать в очереди. Кроме того, таймер отправки (соответствует sendTimeout) работает, когда запрос находится в очереди. Если первые два запроса службы будут выполняться в течение длительного времени, тогда третий будет генерировать исключение TimeoutException, хотя он не был отправлен на сервер (и мы не увидим никакой информации об этом запросе на стороне сервера и не сможем поймать его с помощью Fiddler ...).

В более реальной ситуации, если у нас есть около 12 одновременных вызовов и по умолчанию 1 минута тайм-аута отправки, и если услуги звонят более чем за 10 секунд, мы можем легко получить исключение тайм-аута с двумя последними вызовами (12/2 * 10 сек = 60 с), потому что они будут ждать всех остальных.

Решение:

  1. Минимизировать число одновременных вызовов службы.
  2. Увеличение sendTimeout Значение в client config.
  3. Реализация функции автоматического повтора для критически важных служб.
  4. Реализация очереди запросов для их управления.

В моем случае я сделал 1-3 вещи, и этого было достаточно.

Вот моя реализация функции автоматического повторного запуска:

public static class ClientBaseExtender 
{ 
    /// <summary> 
    /// Tries to execute async service call. If <see cref="TimeoutException"/> occured retries again. 
    /// </summary> 
    /// <typeparam name="TChannel">ServiceClient class.</typeparam> 
    /// <typeparam name="TArgs">Type of service client method return argument.</typeparam> 
    /// <param name="client">ServiceClient instance.</param> 
    /// <param name="tryExecute">Delegate that execute starting of service call.</param> 
    /// <param name="onCompletedSubcribe">Delegate that subcribes an event handler to the OnCompleted event of the service client method.</param> 
    /// <param name="onCompleted">Delegate that executes when service call is succeeded.</param> 
    /// <param name="onError">Delegate that executes when service call fails.</param> 
    /// <param name="maxAttempts">Maximum attempts to execute service call before error if <see cref="TimeoutException"/> occured (by default 5).</param> 
    public static void ExecuteAsyncRepeatedly<TChannel, TArgs>(this ClientBase<TChannel> client, Action tryExecute, 
                   Action<EventHandler<TArgs>> onCompletedSubcribe, EventHandler<TArgs> onCompleted, 
                   EventHandler<TArgs> onError, int maxAttempts) 
     where TChannel : class 
     where TArgs : AsyncCompletedEventArgs 
    { 
     int attempts = 0; 
     var serviceName = client.GetType().Name; 

     onCompletedSubcribe((s, e) => 
           { 
            if (e.Error == null) // Everything is OK 
            { 
             if (onCompleted != null) 
              onCompleted(s, e); 

             ((ICommunicationObject)client).Close(); 
             Debug.WriteLine("[{1}] Service '{0}' closed.", serviceName, DateTime.Now); 
            } 
            else if (e.Error is TimeoutException) 
            { 
             attempts++; 

             if (attempts >= maxAttempts) // Final timeout after n attempts 
             { 
              Debug.WriteLine("[{2}], Final Timeout occured in '{0}' service after {1} attempts.", serviceName, attempts, DateTime.Now); 

              if (onError != null) 
               onError(s, e); 
              client.Abort(); 

              Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now); 
              return; 
             } 

             // Local timeout 
             Debug.WriteLine("[{2}] Timeout occured in '{0}' service (attempt #{1}).", serviceName, attempts, DateTime.Now); 

             Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now); 
             tryExecute(); // Try again. 
            } 
            else 
            { 
             if (onError != null) 
              onError(s, e); 
             client.Abort(); 
             Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now); 
            } 
           }); 

     Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now); 
     tryExecute(); // First attempt to execute 
    } 
} 

А вот использование:

var client = new MyServiceClient(); 
client.ExecuteAsyncRepeatedly(() => client.MyOperationAsync(...), 
    (EventHandler<MyOperationCompletedEventArgs> handler) => client.MyOperationCompleted += handler, 
    (s, e) => // OnCompleted 
     { 
      Do(e.Result); 
     }, 
    (s, e) => // OnError 
     { 
      HandleError(e.Error); 
     } 
); 

Надеется, что это будет полезно.

0

Mmmm ... возможно ли, что запрос/ответ займет более 64 К или слишком много объектов, сериализованных?

Можете ли вы попытаться сделать симуляцию на сервере с помощью консольного приложения (просто чтобы проверить, есть ли это сеть, SL ...)?

+0

«возможно ли, что запрос/ответ займет более 64 К или слишком много объектов, сериализованных» Нет, я думаю. Ответы службы довольно просты и менее 64 КБ. «Можете ли вы попытаться сделать имитацию, наводящую сервер с помощью консольного приложения (просто чтобы проверить, есть ли это сеть, SL ...)?» Спасибо за совет! Это непросто в нашей среде, но я постараюсь. –

0

У вас все еще есть эта проблема?

Если да, то, возможно, вам стоит посмотреть сеть с помощью Fiddler или монитора сети Microsoft или что-то еще?

 Смежные вопросы

  • Нет связанных вопросов^_^