2

I know that catching all exceptions in an app is generally bad, but in my WPF app I do:

  Application.Current.DispatcherUnhandledException += (s, e) => {
    ReportException(e.Exception, false);
    e.Handled = true;
  };

This is mostly useful to prevent minor features (like drag&drop) and async code from crashing the app - I log & display the info to the user.

I want to do the same thing in Xamarin.Mac, but there doesn't seem to be an equivalent. I tried:

  AppDomain.CurrentDomain.UnhandledException += (sender, args) => Log(args.Exception);
  TaskScheduler.UnobservedTaskException += (sender, args) =>
  {
      args.SetObserved();
      Log(args.Exception);
  };
  Runtime.MarshalManagedException += (sender, args) => Log(args.Exception);
  Runtime.MarshalObjectiveCException += (sender, args) => Log(args.Exception);

But when crashing in an async void method, TaskScheduler.UnobservedTaskException, MarshalManagedException and MarshalObjectiveCException are not called, and AppDomain.Current.UnhandledException's e.IsTerminating is get-only, so I can't prevent the app from exiting.

For Android there's AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironmentOnUnhandledException;

But for Mac there doesn't seem to be a way to cancel the app going down?

  • I've heard you can wrap `UIApplication.Main(args, null, "AppDelegate");` in `Main.cs` in a try/catch block and if the app would have exited w/ code 0 or w/e from crashing instead of exiting here it goes into your catch block, it still might end the app but could be useful for debugging. – NSGangster Jan 03 '20 at 19:39
  • `AppDomain.Current.UnhandledException` works perfectly for logging purposes, but neither it nor wrapping Main prevents app shutdown – Vladimir Vasilev Jan 03 '20 at 19:52
  • 1
    There is an [old thread](https://stackoverflow.com/questions/23909348/avoid-mac-app-crashing-after-unhandled-exception) and I think it maybe can answer your question. – nevermore Jan 06 '20 at 07:03
  • Do you know exactly which line this shutdown happens on? Does it raise an exception catchpoint? What exception is caught in the application output? – Saamer Jan 06 '20 at 07:17
  • @Saamer It doesn't matter where the exception happens - I want to catch all exceptions and prevent the app from terminating. I get the exception inside `AppDomain.Current.UnhandledException` handler, and I see it when debugging as occuring in the main Xamarin loop, and it is logged inside application output There's just no way to prevent the app from exiting, as can be done on WPF – Vladimir Vasilev Jan 06 '20 at 19:12
  • It's intentional that you can't do this. Way back in .NET 1.0 the runtime would silently suppress unhandled exceptions, and this was changed for .NET 2.0 to avoid letting apps with potentially invalid state continue running indefinitely. 18+ years later and the policy still applies... – McGuireV10 Jan 06 '20 at 20:02
  • @McGuireV10 even if it's inadvisable and a bad practice, most host platforms provide a way to prevent termination on unhandled exceptions (even new ones). It seems Xamarin.MacOS though does not have it, probably due to some problem with native->.NET transitions – Vladimir Vasilev Jan 09 '20 at 11:04
  • @VladimirVasilev research `legacyUnhandledExceptionPolicy` ([example](https://learn.microsoft.com/en-us/dotnet/standard/threading/exceptions-in-managed-threads#application-compatibility-flag)) to apply the .NET 1.x behavior. You still can't catch them yourself, and MS has said it won't be supported in .NET Core since it never worked very well in .NET Framework, but that's as close as you'll get. – McGuireV10 Jan 09 '20 at 15:42

1 Answers1

1

Unlike Javascript, native MacOS/iOS development is not exception safe and discourages recovering from exceptions as stated in Native iOS docs here:

The standard Cocoa convention is that exceptions signal programmer error and are not intended to be recovered from. Making code exceptions-safe by default would impose severe runtime and code size penalties on code that typically does not actually care about exceptions safety. Therefore, ARC-generated code leaks by default on exceptions, which is just fine if the process is going to be immediately terminated anyway. Programs which do care about recovering from exceptions should enable the option.

There is a way of rejecting exceptions from being thrown by adding a command during compile time, as it is stated in the same link above.

Unfortunately, since Xamarin is Native development, you are stuck to the limitations of native development. The solution is really not to allow exceptions being raised in programming, by using comparisons if (x != null) or functions like TryParse, and to only use try-catch in the highest level when absolutely needed.

So even if you try, as shown here, you will not be able to prevent a crash, but you can add logs before the app will certainly crash. Here's another good resource for this, that explains it for native developers.

Saamer
  • 4,687
  • 1
  • 13
  • 55