none
Question about Catch and exceptions

    Question

  • I am using Observable.FromAsyncPattern in a Silverlight app to wrap some old IAsyncResult code.  Everything works fine in Subscribe when it succeeds, but when the async End function throws an exception, I don't seem to know where to catch it.

    I'm guessing the Observable<T>.Catch() method might be what I want, but the only reference I've seen is a video talking about it and I can't seem to find any example code of how to use it.  Does anyone have an example of how I might write a method/lambda expression that catches an exception in this scenario?

    Thanks!
    Wednesday, December 23, 2009 1:06 AM

Answers

  • Hi Andy,

    there's several ways to deal with exceptions. the most simple one is to pass a second argument to your Subscribe call.

    e.g.:

    IObservable<string> x = Observable.FromAsyncPattern(...);  
    x.Subscribe(value=>HtmlPage.Window.Alert(value), error=>HtmlPage.Window.Alert(error.Message));

    if you want to do more operations on the stream, you can use the Catch operator.

    One way is to silence the catch: e.g. x.Catch(Observable.Empty<string>()).Subscibe(...)

    another way is to write a catch block, in Rx, the catch block returns a new observable that "repairs" the original source:

    x.Catch<ArgumentNullException>(error=> Observable.Return("The operation failed.")).Subscribe(...);

    this sample will send the string "The operation failed" to the OnNext handler if an exception happens.

    Hope this helps.

    Jeffrey
    • Proposed as answer by Jeffrey van Gogh - MS Wednesday, December 23, 2009 1:28 AM
    • Marked as answer by Andy N3 Wednesday, December 23, 2009 5:08 PM
    Wednesday, December 23, 2009 1:28 AM

All replies

  • Hi Andy,

    there's several ways to deal with exceptions. the most simple one is to pass a second argument to your Subscribe call.

    e.g.:

    IObservable<string> x = Observable.FromAsyncPattern(...);  
    x.Subscribe(value=>HtmlPage.Window.Alert(value), error=>HtmlPage.Window.Alert(error.Message));

    if you want to do more operations on the stream, you can use the Catch operator.

    One way is to silence the catch: e.g. x.Catch(Observable.Empty<string>()).Subscibe(...)

    another way is to write a catch block, in Rx, the catch block returns a new observable that "repairs" the original source:

    x.Catch<ArgumentNullException>(error=> Observable.Return("The operation failed.")).Subscribe(...);

    this sample will send the string "The operation failed" to the OnNext handler if an exception happens.

    Hope this helps.

    Jeffrey
    • Proposed as answer by Jeffrey van Gogh - MS Wednesday, December 23, 2009 1:28 AM
    • Marked as answer by Andy N3 Wednesday, December 23, 2009 5:08 PM
    Wednesday, December 23, 2009 1:28 AM
  • Thanks Jeffrey, that's exactly what I was looking for!
    Wednesday, December 23, 2009 5:08 PM
  • Jeff,

    Is there a way to resume processing with the next element in the original observable sequence  in the Catch operator instead of generating a new sequence?

     

    Thx.

    -Abhijeet

    Thursday, May 19, 2011 1:27 AM
  • Hi Abhijeet,

    This is not possible. The OnError notification represents a critical error, that terminates the stream. Similarly, enumerables can't yield values after an exception has been raised. Consider the following.

    void Main()
    {
    	var e = Get().GetEnumerator();
    	e.MoveNext();
    	e.MoveNext();
    	try{ e.MoveNext(); }catch{}
    	e.MoveNext();
    	Console.WriteLine(e.Current); // will output 2 (not 3)
    }
    
    public IEnumerable Get()
    {
    	yield return 1;
    	yield return 2;
    	throw new Exception("test");
    	yield return 3; // you can never read this value
    }
    

    One option is for the "source" to use Notification<T> (or your own custom envelope type) instead.

    public IObservable<Notification<int>> MyObservable()
    {
    	return Observable.Create<Notification<int>>(o =>
    	{
    		o.OnNext(new Notification<int>.OnNext(42));
    		o.OnNext(new Notification<int>.OnError(new Exception("error1")));
    		o.OnNext(new Notification<int>.OnNext(43));
    		o.OnNext(new Notification<int>.OnError(new Exception("error2")));
    		o.OnNext(new Notification<int>.OnNext(44));
    		o.OnNext(new Notification<int>.OnError(new Exception("error3")));
    		return () => {};
    	});
    }
    

    Hope that helps.
    James


    James Miles http://enumeratethis.com
    Thursday, May 19, 2011 9:49 AM