Ваша проблема в том, что вы используете расширение FromEvent
, а не расширение FromEventPattern
.
Первый предназначен для нестандартных событий, а второй - для тех, которые следуют шаблону «отправитель / eventargs».
Тем не менее, у вас все еще есть несколько проблем с вашим наблюдаемым.
Экземпляр WebClient
никогда не удаляется. Вы должны сделать
конечно, это происходит, но поскольку вы используете наблюдаемое, вам нужно
используйте метод расширения Using
.
Помещение Where
перед Take(1)
может означать, что ваша наблюдаемая
никогда не закончится.
Retry
также не будет делать правильные вещи для вас. Если
Наблюдаемая "DownloadStringCompleted" имеет ошибку, затем повторяет попытку
повторно присоединится к событию, но событие никогда не вернет новое
значение, потому что вы больше не звоните DownloadStringAsync
.
Что вы хотите сделать с этим видом наблюдаемого, так это заставить его повторно выполнять веб-вызов каждый раз, когда подписывается новый наблюдатель, но, когда подписка используется совместно (например, если публикуется наблюдаемое), вы не не хочу повторного выполнения веб-вызова. Вы вроде хотите съесть свой торт и съесть его тоже.
Вот как это сделать:
public IObservable<string> CreateDownloadStringObservable(string uri)
{
return Observable.Create<string>(o =>
{
var result = new ReplaySubject<string>();
var inner = Observable.Using(() => new WebClient(), wc =>
{
var obs = Observable
.FromEventPattern<
DownloadStringCompletedEventHandler,
DownloadStringCompletedEventArgs>(
h => wc.DownloadStringCompleted += h,
h => wc.DownloadStringCompleted -= h)
.Take(1);
wc.DownloadStringAsync(new Uri(uri));
return obs;
}).Subscribe(ep =>
{
if (ep.EventArgs.Cancelled)
{
result.OnCompleted();
}
else
{
if (ep.EventArgs.Error != null)
{
result.OnError(ep.EventArgs.Error);
}
else
{
result.OnNext(ep.EventArgs.Result);
result.OnCompleted();
}
}
}, ex =>
{
result.OnError(ex);
});
return new CompositeDisposable(inner, result.Subscribe(o));
});
}
Теперь вы можете назвать это так:
IObservable<string> obs =
CreateDownloadStringObservable("http://www.google.com")
.Retry(3);
Обратите внимание, что Retry
теперь находится за пределами метода запроса, где он должен принадлежать (если только вы не добавили аргумент retry
к вызову метода).