【问题标题】:TimeoutException in simultaneous calls to WCF services from Silverlight application从 Silverlight 应用程序同时调用 WCF 服务时出现 TimeoutException
【发布时间】:2010-10-28 13:34:04
【问题描述】:

分析日志文件我注意到大约 1% 的服务调用在 Silverlight 客户端以 TimeoutException 结束。 服务 (wcf) 非常简单,不会执行长时间的计算。 根据日志,所有对服务的调用总是在不到 1 秒的时间内处理完毕(即使客户端发生了 TimeoutException!),因此不是服务器超时。

那么有什么问题吗?可能是配置问题还是网络问题?我怎样才能避免它? 哪些额外的日志记录信息有助于本地化此问题?

我想到的唯一一种解决方法是在超时后重试服务调用。

我将不胜感激在此问题上的任何帮助!

更新:在启动时,应用程序执行 17 个服务调用,其中 12 个同时执行(可能是失败的原因?)。

更新: WCF 日志未包含有关此问题的有用信息。似乎有些服务调用没有到达服务器端。

【问题讨论】:

  • 我在这里有点困惑.. 你是如何使用 ClientBaseExtender 的?您的代理是从 ClientBaseExtender 派生的吗?但是代理类已经派生自 System.ServiceModel.ClientBase。那么如何用 MyServiceClient 插件 ClientBaseExtender 呢?
  • 不,ClientBaseExtender 为 ClientBase 提供了扩展方法(msdn.microsoft.com/en-us/library/bb383977.aspx)。所以你可以在任何ClientBase的继承者中使用这个方法。
  • analyze 有哪些日志文件?使用任何工具

标签: wcf silverlight timeout timeoutexception simultaneous-calls


【解决方案1】:

嗯……请求/响应是否有可能超过 64 K 或序列化的对象过多?

您能否尝试使用控制台应用程序模拟访问服务器(只是为了检查它是否是网络、SL...)?

【讨论】:

  • "请求/响应是否有可能需要超过 64 K 或太多的对象序列化" 不,我想。服务响应非常简单,小于 64Kb。 “你能尝试用控制台应用程序模拟服务器(只是为了检查它是否是网络,SL......)?”谢谢你的建议!在我们的环境中这并不容易,但我会尝试。
【解决方案2】:

问题在于 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 sec = 60 秒),因为他们会等待所有其他人。

解决办法是:

  1. 尽量减少并发服务调用的数量。
  2. 增加客户端配置中的sendTimeout值。
  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);
        }
);

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    你还有这个问题吗?

    如果是这样,那么也许您应该使用 Fiddler 或 Microsoft Network Monitor 或其他工具监视网络?

    【讨论】:

      猜你喜欢
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      相关资源
      最近更新 更多