0

I have the following code:

    try
    {
        Data.CreateUserAndAccount.ExecuteProcedure(accountName, firstName, lastName, email, password);
        return String.Empty;
    }
    catch (SqlException databaseError)
    {
        string result = IdentifyError(databaseError);
        return result;
    }
    catch  (Exception)
    {
        throw;
    }

I am intentionally throwing SQL exceptions by violating a unique key. However, the exception is caught by Exception and not SqlException. When I examine the InnerException details, the exception is of type System.Data.SqlClient.SqlException.

InnerException Details

Why is the SQL exception only being caught by the generic Exception?

  • 2
    Because `SqlException` is the `InnerException`, presumably. What's the actual exception type? – ProgrammingLlama Apr 06 '19 at 02:02
  • It could be UpdateException/DbUpdateException, check out this answer: https://stackoverflow.com/questions/3967140/duplicate-key-exception-from-entity-framework – user10954641 Apr 06 '19 at 02:11
  • The actual exception type is `EntityCommandExecutionException` @John @user10954641 . –  Apr 06 '19 at 12:18

2 Answers2

8

The problem is that you're trying to catch SqlException, but that's not the exception type: it's the InnerException.

If user10954641 is right, and its an UpdateException, you could simply catch that:

try
{
}
catch (UpdateException e)
{
}

If it's a different exception, then catch whatever exception type is actually thrown. Alternatively, you could conditionally catch exceptions where the InnerException is SqlException:

try
{
}
catch (Exception e) when (e.InnerException is SqlException)
{
}

If you're wondering why catch (SqlException) doesn't work, consider the following code:

public void ThrowException()
{
    try
    {
        MakeDatabaseCall();
    }
    catch (Exception e)
    {
        throw new Exception("Uh oh!", e);
    }
}

public void MakeDatabaseCall()
{
    throw new SqlException();
}

A call to ThrowException() will ultimately produce an error form MakeDatabaseCall(), but the exception type will not be SqlException because we're wrapping it in another exception (in this case the exception base class): Exception. But, because we're passing the exception thrown by MakeDatabaseCall() into the constructor, our "Uh oh!" exception will contain the SqlException in its InnerException field.

When you use try/catch(ExceptionType e), you're instructing .NET to pattern match the exception before deciding which catch statement to enter. For the sake of illustration, the two pieces of code below are roughly equivalent:

try
{
}
catch(SqlException e)
{
    //catches an SqlException
}

and

try
{
}
catch(Exception e) when (e is SqlException)
{
    //catches an SqlException
}

Clearly in our ThrowException example, Exception is not derived from SqlException, so catch (SqlException e) won't match.

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
0

It turns out the exception is of type EntityCommandExecutionException which is derived from DataException.

I originally intended to perform some logic on SqlException.Number, which is why I was trying to catch a SqlException.

However, to solve this, catch DataException and then cast the InnerException to SqlException:

try
{
    Data.CreateUserAndAccount.ExecuteProcedure(accountName, firstName, lastName, email, password);
    return String.Empty;
}
catch (DataException procedureError)
{
    SqlException sqlError = (SqlException)procedureError.InnerException;
    string result = IdentifyError(sqlError);
    return result;
}