0

And how can I present it to the user? This post : WCF Duplex: How to handle thrown exception in duplex Callback is very close to my scenario. And this post is useful for helping me re-establish the connection when the channel is faulted.

I have a Publishing application Pub, and a subscribing WPF application Sub. The Pub sends a message and the Sub has subscribed for a callback using a duplex channel.
Sub.ViewModel.ReactToChange(sender, e) tries to read some data, but is unable to and throws an exception.

DispatcherUnhandledException doesn't catch it (I didn't really expect it to.)
AppDomain.CurrentDomain.UnhandledException doesn't catch it (that does surprise me)
The end result is I have an application that is still running, and no exception message is shown to the user so they can correct the problem. Is there a way I can show that exception to the user?

Community
  • 1
  • 1
KarlZ
  • 170
  • 9

1 Answers1

0

This is a bit tricky, but the only way I've found. I hope this helps others. The idea is to not let an exception get thrown, but instead create an UnhendledExceptionEventArg and pass it up to your UI layer. Here is some example code:

public class BuggySubscriber : IDisposable
{
    public BuggySubscriber(string dataSourceName)
    {
        SyncContext = SynchronizationContext.Current;
        Subscriber = new MockSubscriber(dataSourceName);
        Subscriber.Refreshed += OnDataChanged;
    }

    public SynchronizationContext SyncContext { get; set; }

    public event EventHandler<UnhandledExceptionEventArgs> ExceptionOccurred;

    // Bouncing Exception Step 3
    private void OnExceptionOccured(Exception ex) 
    {
        var callback = new SendOrPostCallback(delegate
            {
                var handler = ExceptionOccurred;
                if (!ReferenceEquals(handler, null))
                    handler(this, new UnhandledExceptionEventArgs(ex, true));
            });

        SyncContext.Post(callback, null);
    }

    void OnDataChanged(object sender, ServiceModel.DataChanged.DataChangedEventArgs e)
    {
        // Bouncing Exception Step 1 & 2
        OnExceptionOccured(new NotImplementedException()); 
    }

So this is the "Sub" code. In the WPF application I add the following when the app starts:

        protected override void OnStartup(StartupEventArgs e)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            BuggySubscriber.ExceptionOccurred += Sub_ExceptionOccurred;
...
        }

        // Bouncing Exception Step 5
        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var exception = e.ExceptionObject as Exception;
            if (!ReferenceEquals(exception, null))
                ShowErrorMessage(exception);
        }

        // Bouncing Exception Step 4
        void Sub_ExceptionOccurred(object sender, UnhandledExceptionEventArgs e)
        {
            var exception = e.ExceptionObject as Exception;
            if (!ReferenceEquals(exception, null))
                throw exception;
        }

So now let's try to follow the bouncing exception.

  1. In real life, the subscriber was notified and an exception occurs and is caught. (In my sample, I don't show that.)
  2. Then the OnExceptionOccurred(Exception ex) is called.
  3. That then creates the SendOrPostCallback using the ExceptionOccurred event and then does a Post to the current SynchronizationContext.
  4. The WPF application that registered for the ExceptionOccurred (Now if you like, you could handle the exception message here... I chose to use two paths for exceptions rather than three.) It casts and throws the Exception.
  5. Now the CurrentDomain_UnhandledException processes it and shows an error message to the user (right before it exits).

I'm sure there are many variations on this, but this does show some of the trickier code that I could not find in one place.
NOTE: This does not solve any channel problems. If you have an exception you can recover from you will still need to reestablish the channel since it will be faulted or closed.

KarlZ
  • 170
  • 9