5YrsLaterDBA
5YrsLaterDBA

Reputation: 34750

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, DbConnection 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?

Upvotes: 5

Views: 3488

Answers (5)

Justin
Justin

Reputation: 6711

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.

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941317

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;
    //...
}

Upvotes: 3

Andrew Anderson
Andrew Anderson

Reputation: 3449

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.

Upvotes: 6

Robaticus
Robaticus

Reputation: 23157

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.

Upvotes: 1

Etienne de Martel
Etienne de Martel

Reputation: 36852

Because what's thrown is not an SAException. Try printing out the exception directly instead of calling GetBaseException().

Upvotes: 4

Related Questions