Why cannot catch the inner exception?
I try to catch the database exception when database server is down. We use Sybase IAnywhere.
I use regular C# try catch to get the name of the database exception.
try
{
//code here
}
catch (Exception ex)
{
Logging.Log.logItem(LogType.Exception, "Exception in isDBRunning", "App_Startup::isDBRunning() ", "GetBaseException=" + ex.GetBaseException().ToString() + "\nMessage=" + ex.Message + "\nStackTrace: " + ex.StackTrace + "\nInnerException: " + ex.InnerException);
}
The exception print out is this:
GetBaseException=iAnywhere.Data.SQLAnywhere.SAException: Database server not found
at iAnywhere.Data.SQLAnywhere.SAConnection.Open()
at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnect开发者_高级运维ion storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
Message=The underlying provider failed on Open.
StackTrace: at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
at System.Data.EntityClient.EntityConnection.Open()
at System.Data.Objects.ObjectContext.EnsureConnection()
at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__2[TResult](IEnumerable`1 sequence)
at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
at Analogic.SystemSoftware.App.isDBRunning() in C:\workspace\SystemSoftware\SystemSoftware\src\startup\App.xaml.cs:line 158
InnerException: iAnywhere.Data.SQLAnywhere.SAException: Database server not found
at iAnywhere.Data.SQLAnywhere.SAConnection.Open()
at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure)
So I think the iAnywhere.Data.SQLAnywhere.SAException
is the real exception I should handle. Then I added a catch for it:
try
{
//code here
}
catch (iAnywhere.Data.SQLAnywhere.SAException ex)
{
Logging.Log.logItem(LogType.Exception, "Exception in isDBRunning 1", "App_Startup::isDBRunning() ", "GetBaseException=" + ex.GetBaseException().ToString() + "\nMessage=" + ex.Message + "\nStackTrace: " + ex.StackTrace + "\nInnerException: " + ex.InnerException);
}
catch (Exception ex)
{
Logging.Log.logItem(LogType.Exception, "Exception in isDBRunning", "App_Startup::isDBRunning() ", "GetBaseException=" + ex.GetBaseException().ToString() + "\nMessage=" + ex.Message + "\nStackTrace: " + ex.StackTrace + "\nInnerException: " + ex.InnerException);
}
But the iAnywhere.Data.SQLAnywhere.SAException
is NOT caught. I still get the Exception
caught. why?
Catch
deals with the type of the actual exception that has been thrown, whereas GetBaseException
returns the (first) InnerException
if any exist.
Print out the actual exception to see its specific type (or inspect it in a debugger, or whatever) and then catch that.
Because what's thrown is not an SAException. Try printing out the exception directly instead of calling GetBaseException().
It isn't SAException, that's the inner exception. It isn't clear from the stack trace what the outer exception type is. Easy to find out with the debugger or some diagnostic code:
catch (Exception ex) {
Console.WriteLine(ex.GetType().FullName;
//...
}
Check to see what the actual exception is that you have coming through. Your GetBaseException()
call might be masking the actual exception that is occurring.
You may need to do something like this:
try
{
//code here
}
catch (Exception ex)
{
if (ex.GetBaseException() is iAnywhere.Data.SQLAnywhere.SAException)
{
// log or handle known exception
}
else
{
// log unexpected exception
}
}
As the other answers have stated, you can improve this if you know the actual type of the Exception, by changing Exception
in the above code to the specific type of the exception.
精彩评论