問題は、Internet Explorer 7/6 での単一サーバーへの同時接続の最大数にあります。2つだけです!http://msdn.microsoft.com/en-us/library/cc304129(VS.85).aspx
たとえば、3 つの同時サービス呼び出しがある場合、そのうち 2 つがすぐにサーバーに送信されますが、3 つ目はキューで待機します。sendTimeout
また、リクエストがキューにあるときは、送信タイマー ( に対応) が実行されます。最初の 2 つのサービス要求が長時間実行されると、サーバーに送信されていないにもかかわらず、3 番目のサービス要求で TimeoutException が生成されます (サーバー側ではこの要求に関する情報が表示されず、Fiddler でキャッチできません) ...)。
より現実的な状況では、約 12 の同時呼び出しがあり、デフォルトで 1 分間の送信タイムアウトがあり、サービス呼び出しが平均で 10 秒以上処理され、最後の 2 つの呼び出しで簡単にタイムアウト例外が発生する場合 (12 / 2 * 10 秒 = 60 秒) ) 彼らは他のすべてを待つからです。
解決策は次のとおりです。
- 同時サービス呼び出しの数を最小限に抑えます。
- クライアント
sendTimeout
構成の値を増やします。
- 重要なサービスの自動再試行機能を実装します。
- それらを管理するためにリクエストのキューを実装します。
私の場合、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);
}
);
これが役立つことを願っています。