It seems the best answer is to use Observable.CreateWithDisposable ()
eg.
public IObservable<XElement> GetReport(string reportName) { return from client in Observable.Return(new WebServiceClient()) from completed in Observable.CreateWithDisposable<GetReportDataCompletedEventArgs>(observer => { var subscription = Observable.FromEvent<GetReportDataCompletedEventArgs>(client, "GetReportDataCompleted") .Take(1) .Select(e => e.EventArgs) .Subscribe(observer); client.GetReportDataAsync(reportName); return subscription; }) from close in this.CloseClient(client) select completed.Result; }
To make it easier to work with I, I converted CreateWithDisposable to a generic function that can be used with all my web service calls, including automatically detecting the event name from the args type of events:
private IObservable<T> CallService<T>(ICommunicationObject serviceClient, Action start) where T : AsyncCompletedEventArgs { if (typeof(T) == typeof(AsyncCompletedEventArgs)) { throw new InvalidOperationException("Event arguments type cannot be used to determine event name, use event name overload instead."); } string completedEventName = typeof(T).Name.TrimEnd("EventArgs"); return CallService<T>(serviceClient, start, completedEventName); } private IObservable<T> CallService<T>(ICommunicationObject serviceClient, Action start, string completedEventName) where T : AsyncCompletedEventArgs { return Observable.CreateWithDisposable<T>(observer => { var subscription = Observable.FromEvent<T>(serviceClient, completedEventName).Take(1).Select(e => e.EventArgs).Subscribe(observer); start(); return subscription; }); } // Example usage: public IObservable<XElement> GetReport(string reportName) { return from client in Observable.Return(new WebServiceClient()) from completed in this.CallService<GetReportDataCompletedEventArgs>(client, () => client.GetReportDataAsync(reportName)) from close in this.CloseClient(client) select completed.Result; }
Hope this helps someone else!
source share