Я сгенерировал прокси-классы для веб-службы в Visual Studio с помощью «Добавить веб-ссылку». Сгенерированный класс RTWebService
имеет метод SetValueAsync
. Я расширил этот класс и добавил SetValueRequest
, который отслеживает запросы и отменяет все ожидающие запросы при возникновении ошибки. С каждым запросом я сохраняю объект userState
в ArrayList, который я создал следующим образом:
requests = ArrayList.Synchronized(new ArrayList());
Я создал метод:
public void CancelPendingRequests() {
lock (requests.SyncRoot) {
if (requests.Count > 0) {
foreach (object request in requests) {
this.CancelAsync(request);
}
requests.Clear();
}
}
}
Я вызываю этот метод, когда запрос возвращается по событию SetValueCompleted
:
private void onRequestComplete(
object sender,
Service.SetValueCompletedEventArgs args
) {
lock (syncResponse) {
if (args.Cancelled) {
return;
}
if (args.UserState != null) {
requests.Remove(args.UserState);
}
if (args.Error != null) {
CancelPendingRequests();
}
}
}
Чтобы начать новый запрос, я звоню:
public void SetValueRequest(string tag, string value) {
var request = new object();
this.SetValueAsync(tag, value, request);
requests.Add(request);
}
Каждый раз, когда я делаю запрос, и в то же время возвращается ответ с ошибкой, я получаю TargetInvocationException
в CancelPendingRequests
. Внутреннее исключение - InvalidOperationException
для ArrayList в методе CancelPendingRequests
, говорящее:
Коллекция была изменена; операция перечисления может не выполняться.
Похоже, SetValueRequest
изменил объект requests
, пока я его перечислял. Я думал, что это невозможно, потому что я использовал синхронизированную оболочку для ArrayList и использую SyncRoot для синхронизации перечисления. Я немного застрял в этом, так что если у кого-нибудь есть идея?