Skip to content

Instantly share code, notes, and snippets.

@kiwidev
Created October 26, 2012 10:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kiwidev/3958178 to your computer and use it in GitHub Desktop.
Save kiwidev/3958178 to your computer and use it in GitHub Desktop.
SynchronizationContext that allows for catching and dealing with unhandled exceptions. Very useful in WinRT.
using System;
using System.Threading;
namespace TestExceptions
{
/// <summary>
/// Wrapper around a standard synchronization context, that catches any unhandled exceptions.
/// Acts as a facade passing calls to the original SynchronizationContext
/// </summary>
/// <example>
/// Set this up inside your App.xaml.cs file as follows:
/// <code>
/// protected override void OnActivated(IActivatedEventArgs args)
/// {
/// EnsureSyncContext();
/// ...
/// }
///
/// protected override void OnLaunched(LaunchActivatedEventArgs args)
/// {
/// EnsureSyncContext();
/// ...
/// }
///
/// private void EnsureSyncContext()
/// {
/// var exceptionHandlingSynchronizationContext = ExceptionHandlingSynchronizationContext.Register();
/// exceptionHandlingSynchronizationContext.UnhandledException += OnSynchronizationContextUnhandledException;
/// }
///
/// private void OnSynchronizationContextUnhandledException(object sender, UnhandledExceptionEventArgs args)
/// {
/// args.Handled = true;
/// }
/// </code>
/// </example>
internal class ExceptionHandlingSynchronizationContext : SynchronizationContext
{
/// <summary>
/// Registration method. Call this from Launched and Loaded inside the App.xaml.cs
/// </summary>
/// <returns></returns>
public static ExceptionHandlingSynchronizationContext Register()
{
var syncContext = SynchronizationContext.Current;
if (syncContext == null)
throw new InvalidOperationException("Ensure a synchronization context exists before calling this method.");
var customSynchronizationContext = syncContext as ExceptionHandlingSynchronizationContext;
if (customSynchronizationContext == null)
{
customSynchronizationContext = new ExceptionHandlingSynchronizationContext(syncContext);
SynchronizationContext.SetSynchronizationContext(customSynchronizationContext);
}
return customSynchronizationContext;
}
private readonly SynchronizationContext _syncContext;
public ExceptionHandlingSynchronizationContext(SynchronizationContext syncContext)
{
_syncContext = syncContext;
}
public override SynchronizationContext CreateCopy()
{
return new ExceptionHandlingSynchronizationContext(_syncContext.CreateCopy());
}
public override void OperationCompleted()
{
_syncContext.OperationCompleted();
}
public override void OperationStarted()
{
_syncContext.OperationStarted();
}
public override void Post(SendOrPostCallback d, object state)
{
_syncContext.Post(WrapCallback(d), state);
}
public override void Send(SendOrPostCallback d, object state)
{
_syncContext.Send(d, state);
}
private SendOrPostCallback WrapCallback(SendOrPostCallback sendOrPostCallback)
{
return state =>
{
try
{
sendOrPostCallback(state);
}
catch (Exception ex)
{
if (!HandleException(ex))
throw;
}
};
}
private bool HandleException(Exception exception)
{
if (UnhandledException == null)
return false;
var exWrapper = new UnhandledExceptionEventArgs()
{
Exception = exception
};
UnhandledException(this, exWrapper);
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
#endif
return exWrapper.Handled;
}
/// <summary>
/// Listen to this event to catch any unhandled exceptions and allow for handling them
/// so they don't crash your application
/// </summary>
public event EventHandler<UnhandledExceptionEventArgs> UnhandledException;
}
public class UnhandledExceptionEventArgs : EventArgs
{
public bool Handled { get; set; }
public Exception Exception { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment