How to catch all exceptions in try catch block in Xamarin.Android
I am very frustrated on how Xamarin.Android handles unhandled exception which is very weird, I added three exceptions for all api queries respectively:
try
{
// api query using `refit`
// json parsing using `newtonsoft`
}
catch(System.OperationCanceledException e)
{
// user cancelled the query, show option to retry
}
catch(ApiException apiException)
{
// theres an api exception , show error message to users , show option to retry
}
catch(Exception e)
{
// unknown exception ignore , show error message to users , show option to retry
}
This try catch blocks works most of the time, but there is one certain scenario when our server is down, and it just throws exception and crashes the app over and over again until the server is back up.
This is the exception that keeps on bugging us :
Xamarin caused by: android.runtime.JavaProxyThrowable: Newtonsoft.Json.JsonReaderException
As you can see in JsonReaderException hierarchy, it inherited System.Exception which is the last catch block i used.
and I checked this JsonReaderException it extends from Exception , In which our try catch block should handle it.
Now im wondering is there any way that we can catch all those pesky unhandled exceptions?
I'm getting unhandled exceptions in this way
public void Init()
{
AndroidEnvironment.UnhandledExceptionRaiser += OnAndroidEnvironmentUnhandledExceptionRaiser;
AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;
TaskScheduler.UnobservedTaskException += OnTaskSchedulerUnobservedTaskException;
var currentHandler = Java.Lang.Thread.DefaultUncaughtExceptionHandler;
var exceptionHandler = currentHandler as UncaughtExceptionHandler;
if (exceptionHandler != null)
{
exceptionHandler.SetHandler(HandleUncaughtException);
}
else
{
Java.Lang.Thread.DefaultUncaughtExceptionHandler = new UncaughtExceptionHandler(currentHandler, HandleUncaughtException);
}
}
private void OnAndroidEnvironmentUnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
AndroidEnvironment.UnhandledExceptionRaiser -= OnAndroidEnvironmentUnhandledExceptionRaiser;
_logger.LogFatal($"AndroidEnvironment.UnhandledExceptionRaiser.", e.Exception);
e.Handled = true;
}
private void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException -= OnCurrentDomainUnhandledException;
var ex = e.ExceptionObject as Exception;
if (ex != null)
{
_logger.LogFatal("AppDomain.CurrentDomain.UnhandledException.", ex);
}
else
{
_logger.LogFatal($"AppDomain.CurrentDomain.UnhandledException. ---> {e.ExceptionObject}");
}
}
private void OnTaskSchedulerUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
_logger.LogFatal("TaskScheduler.UnobservedTaskException.", e.Exception);
}
private bool HandleUncaughtException(Java.Lang.Throwable ex)
{
_logger.LogFatal("Thread.DefaultUncaughtExceptionHandler.", ex);
return true;
}
Related
I am catching an exception and processing it.
Somewhere up the call tree, I am doing the same.
Once I process my exception at the child level, I want to also go ahead and invoke the exception handler, wherever it is, somewhere up the call tree.
For that, I thought I would do run the throw again.
But instead of breaking somewhere up the call tree, it is breaking in the place where I am doing the throw and crashing, at this line:
throw new Exception("Cannot Write Header Row to Database " + Msg);
code:
public static void NewHeaderRow(string FILE_REV_NUMBER, DateTime FILE_CREATE_DATE, string EDC_DUNS_NUMBER, int RunId)
{
SqlConnection connection = null;
try
{
connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DbConn"].ToString());
connection.Open();
SqlCommand com;
com = new SqlCommand("dbo.INSERT_PPL_HEADER", connection);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.Add(new SqlParameter("#FILE_REV_NUMBER", FILE_REV_NUMBER));
com.Parameters.Add(new SqlParameter("#FILE_CREATE_DATE", FILE_CREATE_DATE));
com.Parameters.Add(new SqlParameter("#EDC_DUNS_NUMBER", EDC_DUNS_NUMBER));
com.Parameters.Add(new SqlParameter("#RunId", RunId));
if (com.Connection.State == ConnectionState.Closed) com.Connection.Open();
com.ExecuteNonQuery();
}
catch (Exception e)
{
string Msg;
Msg = "Encountered unexpected program issue. Please contact your program administator. Error details...";
Msg = Msg + System.Environment.NewLine;
Msg = Msg + System.Environment.NewLine;
Msg = Msg + e.ToString();
Msg = Msg + System.Environment.NewLine;
Msg = Msg + System.Environment.NewLine;
Msg = Msg + e.Message;
throw new Exception("Cannot Write Header Row to Database " + Msg);
}
finally
{
if (connection == null) { } else connection.Close();
}
}
Try just using the throw keyword, instead of building a new exception.
https://stackoverflow.com/a/2999314/5145250
To add additional information to the exception warp it in another exception object and pass the original exception as argument with new message to keep the original stack trace in inner exception.
throw new Exception("Cannot Write Header Row to Database " + Msg, e);
At some top level you should handle global exceptions to avoid crashing.
The way I was finally able to pin point the problem was to extremely simplify my code so as to be able to see the problem clearly. I just copied my solution to a new location, and gutted out all the non-essential stuff -- stuff I knew was not going to be important for the purposes of troubleshooting.... Very effective way of troubleshooting difficult problems that are hard to trace.... Here is what I ended up with (the simple code).
I was not catching general exception in the code that calls NewHeaderRow.
I was catching System.IO exception.
So, because code had nowhere to go, it crashed....
It is very hard for the eyes to catch this error and also difficult to trace.
private void button1_Click(object sender, EventArgs e)
{
LoadFile();
}
private static int ProcessHeaderRow(string line)
{
int LoadRunNumber = 0;
try
{
//some complex logic was here; error occurs here, so I throw an exception....
throw new Exception("An Error Occurs -- Process Header Row Try block");
}
catch (CustomExceptionNoMessage e)
{
throw new CustomExceptionNoMessage(e.Message);
}
catch (Exception e)
{
//Process the exception, then rethrow, for calling code to also process the exception....
//problem is here...XXXXXXXXXXXXXXXXXX
throw new Exception(e.Message); //crashes
}
return LoadRunNumber;
}
public static bool LoadFile()
{
int RunId = 0;
try
{
RunId = ProcessHeaderRow("10~~happy~007909427AC");
MessageBox.Show("Completed Upload to Cloud...");
}
catch (CustomExceptionNoMessage ce)
{
MessageBox.Show(ce.Message);
}
catch (System.IO.IOException e) //CHANGED THIS LINE, AND I AM UP AND RUNNING (Changed to Exception e)
{
MessageBox.Show(e.Message);
}
return true;
}
public class CustomExceptionNoMessage : Exception
{
public CustomExceptionNoMessage()
{
}
public CustomExceptionNoMessage(string message)
: base(message)
{
}
public CustomExceptionNoMessage(string message, Exception inner)
: base(message, inner)
{
}
}
private void button1_Click(object sender, EventArgs e)
{
LoadFile();
}
So I have a stack of calls. At the end of the stack an ArgumentException gets thrown. It propogates from to the last but one point where I have this code:
... Constructor(..){
try
{
this.Issuer = issuer;
this.Name = name;
this.Secret = secret;
this.totpObj = new Totp(secret, 30, 6, mode);
this.id = Guid.NewGuid().ToString();
this.mode = mode;
this.valid = true;
}
catch (System.ArgumentException e)
{
throw e; // Also tried not having this --> option B
}
catch (Exception e)
{
}
}
And this code gets called from here:
private void addButtnClick(object sender, RoutedEventArgs e)
{
try
{
...
TOTPObj totpo = new TOTPObj(af.Accname, af.Issuer, secret, stype); // <--- FAILS
...
}
catch(Exception ex) // <--- SHOULD CATCH THIS?!
{
Console.WriteLine(ex);
Environment.Exit(ERROR_FAILED_ADD_KEY);
}
}
Now if I leave the "throw" in the first section of code I get:
While I think it should be caught at the next level? (second fragment of code).
If I don't throw the exception up but just do stuff there, I never get past the "<--- FAILS" point of code block two, the thread just exits. Why is that?
Having a syntax error that I can not find I think. e.CmsData is showing error along with e.Message.
Error states: only assignment, call, decrement, and the new object expressions can be used as a statement.
What am I missing?
private static void OnMessageReceived (object sender, MessageReceivedEventArgs e)
{
try
{
if (e == null)
return;
if (e.CmsData != null) e.CmsData;
if (!String.IsNullOrEmpty(e.Message))
(e.Message);
}
catch (Exception ex)
{ }
{
// logger.Error(" Exception " + ex);
// throw ex;
}
}
e.CmsData;
is not a valid statement, you need to do something with it, like
var x = e.CmsData;
The same goes for
(e.Message);
Accessing a property like you did is invalid
e.Cmsdata; // Invalid
Properties are just like variables but encapsulated.
You're referencing variables but not doing anything with them.
Try something like this
private static void OnMessageReceived (object sender, MessageReceivedEventArgs e)
{
try
{
if (e == null)
return;
(e.CmsData != null)
{
var data = e.CmsData;
//Do something with "data"
}
if (!String.IsNullOrEmpty(e.Message))
MessageBox.Show(e.Message);
}
catch (Exception ex)
{
// logger.Error(" Exception " + ex);
// throw ex;
}
}
Here are the two alternatives i tried for catching errors, they both seem to do the same thing.. but is one preferable over the other and why ?
Alt 1:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
Task t = Task.Run(() =>
{
_someObj.SomeMethod();
});
await t; //wait here, without blocking...
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
return; //<-- bypass below code on error...
}
//other code below... does not execute...
DoSomethingElse();
}
Alt 2:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool errOccurred = false;
Task t = Task.Run(() =>
{
try
{
_someObj.SomeMethod();
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
errOccurred = true;
}//end-Catch
});
await t; //wait here, without blocking...
if (errOccurred) return; //<-- bypass below code on error...
//other code below... does not execute...
DoSomethingElse();
}
Better option is to refactor part of the code into a separate method returning a bool indicating that whether to proceed or not.
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool success = await SomeMethodAsync();
if (!success)
{
return;
}
//other code below... does not execute...
DoSomethingElse();
}
private async Task<bool> SomeMethodAsync()
{
try
{
await Task.Run(() => _someObj.SomeMethod());
return true;
}
catch (Exception ex)
{
string errMsg = string.Format("{0} {1}some unhandled error occurred in SomeMethod",
ex.Message, Environment.NewLine);
Log(errMsg);
return false;
}
}
It's better to refactor the code than putting it all at the same place.It's better to catch the exception within your delegate if all you need to do is log it.
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
}
However If you have another method DoSomethingElse() which might be affected by the outcome of the Task.It's better to wrap try catch around await
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
DoSomethingElse();
}
catch(Exception ex)
{
}
}
As with anything it depends.
I'd say refactor the Task.Run() section into a separate async Task method, much like Sriram Sakthivel's answer, is in general a good thing. It avoids the use of a captured bool in the lambda as in version 2, and it lets you write code that expresses intent more concisely.
That said, I would carefully consider if the "catch all -> log -> ignore" pattern is what you want. In general: catch specific exceptions and handle them specifically. For all other exceptions, you might log them, but still rethrow them with "throw;" or "throw new MoreSpecificException(originalException);".
With that in mind I would suggest that if you do the catch all approach you should do the catch all as in version 1.
To keep readability high, make the code concise with clear intent, and be explicit about handling exceptions, I would write it something like this:
private async void BtnClick(object sender, RoutedEventArgs e)
{
try
{
if (await TryDoSomethingAsync())
{
DoSomeMoreStuff();
}
}
catch (Exception ex)
{
// I am sure it is fine that any and all exceptions can be logged and ignored.
Log(ex);
// And maybe even notify the user, since I mean, who monitors log files anyway?
// If something that shouldn't go wrong goes wrong, it's nice to know about it.
BlowUpInYourFace(ex);
}
}
private async Task<bool> TryDoSomethingAsync()
{
return await Task.Run<bool>(() =>
{
try
{
_myService.DoSomething();
}
catch (SomeKnownException ske)
{
// An expected exception which is fine to ignore and return unsuccessful.
Log(ske);
return false;
}
catch (SomeOtherKnownException soke)
{
// Expected exception that indicates something less trivial, but could be more precise.
throw new MyMorePreciseException(soke);
}
// Nothing went wrong, so ok.
return true;
});
}
i have a code to restart a service in an event which does other functions too.
I have a try catch in the event for everything within the event like this:
private void btnApply_Click(object sender, EventArgs e)
{
try
{
applyChangesAndCheckRestartService();
}
catch (Exception ex)
{
MessageBox.Show("Error loading page.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void applyChangesAndCheckRestartService()
{
string svrPortNo = CommonCodeClass.getTagValue(CommonCodeClass.xml_SvrPortNoTag, CommonCodeClass.configLocation + CommonCodeClass.configXML);
if (!ApplyChangesForSettings())
{
return;
}
if (svrPortNo != tbSvrPortNo.Text)
{
CommonCodeClass.CheckToRestartService();
}
}
Now if there is an error during ApplyChangesForSettings() i will get an error popup "Error loading page".
If there is an error in CheckToRestartService() i will get the same error because of the try catch.
Is there a better way to handle this.
Like i dont mind the error loading page for ApplyChangesForSettings() but for CheckToRestartService() i would like to see an error like "unable to restart service".
Any suggestions are appreciated.
Thanks
internal static void CheckToRestartService()
{
DialogResult result = MessageBox.Show(CommonCodeClass.resartServiceMessage, "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes)
{
CommonCodeClass.RestartService(CommonCodeClass.serviceName, 60000);
}
}
Do they throw different exceptions? If they do you could use exception filtering:
private void btnApply_Click(object sender, EventArgs e)
{
try
{
applyChangesAndCheckRestartService();
}
// catch service start exceptions
catch (InvalidOperationException ioex)
{
// display message that couldn't start service
}
// catch rest
catch (Exception ex)
{
MessageBox.Show("Error loading page.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
UPDATE this is assuming you're calling something like ServiceController.Start() which throws InvalidOperationException on failure, you could easily throw this yourself on your own error condition or create your own custom exception.
if (/* service didn't start */)
{
throw new InvalidOperationException("Could not start service.");
}
You either need to
catch the exception in applyChangesAndCheckRestartService
or you could pass an enum by ref f.e. called RestartStatus
enum RestartStatus{success, unableToRestart, unableToApplySettings};
RestartStatus status = RestartStatus.success;
applyChangesAndCheckRestartService(status);
if(status != RestartStatus.success) //....
private void applyChangesAndCheckRestartService(out RestartStatus status)
{
// set the status variable accordingly
}
A third way is to use custom exceptions that you can catch separately.
Well maybe you just need to wrap the different functions with separate try/catch blocks:
try {
if (!ApplyChangesForSettings())
return;
}
catch (Exception ex) {
MessageBox.Show("Error loading page.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (svrPortNo != tbSvrPortNo.Text) {
try {
CommonCodeClass.CheckToRestartService();
}
catch (Exception ex) {
MessageBox.Show("Unable to restart services.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Or, you could consider catching different types of exceptions, if they threw different types:
string errmsg = string.empty;
try {
DoSomething();
}
catch (FooException) {
errmsg = "There was a Foo error";
}
catch (WidgetException) {
errmsg = "There was a problem with a Widget";
}
catch (Exception ex) {
errmsg = "General problem: " + ex.Message;
}
if (!string.IsNullOrEmpty(errmsg))
MessageBox.Show(errmsg);
See also:
Exception Handling
The fastest way to handle this situation is throwing an exception when someone of your internal methods fails and catch the message in the btnApply_Click.
MessageBox.Show(ex.Message, "Error", .....);
The rightest way is to create your own exception type and inside the methods, if there is a fail condition throw your own exception. For example create a class like this
public class RestartServiceException : Exception
{
public RestartServiceException(string message)
: base(message)
{
}
// You could also write other constructors with different parameters and use internal logic
// to process your error message
}
and then, use an instance of that class when the fail condition arise inside your CheckToRestartService method
if(fail == true)
throw new RestartServiceException("The service could not be started because .....");