views:

132

answers:

1

I have a tough question to ask so please bier with me.

In this code below, this works because the programmer was interested in projecting only the specific errors caused by the physical data-layer to the eventlog. The rest are pushed farther up the stack. This is specifically because he is able to catch OdbcException(s).

I am implementing my own MembershipProvider. I am however, using Linq to Entities but I would like to send only the low-level/physical-level exceptions to the eventlog. Is there an exception that I can catch when using Linq to Entities that will allow me to catch at that level?

As you can see below, even the exceptions that are thrown within the try block will not get caught so will not be sent to the eventlog.

How can this be done with Linq to Entities?

Code:

public override string ResetPassword(string username, string answer)
{
 if (!EnablePasswordReset)
 {
  throw new NotSupportedException("Password reset is not enabled.");
 }

 if (answer == null && RequiresQuestionAndAnswer)
 {
  UpdateFailureCount(username, "passwordAnswer");

  throw new ProviderException("Password answer required for password reset.");
 }

 string newPassword =
   System.Web.Security.Membership.GeneratePassword(newPasswordLength, MinRequiredNonAlphanumericCharacters);


 ValidatePasswordEventArgs args =
   new ValidatePasswordEventArgs(username, newPassword, true);

 OnValidatingPassword(args);

 if (args.Cancel)
  if (args.FailureInformation != null)
   throw args.FailureInformation;
  else
   throw new MembershipPasswordException("Reset password canceled due to password validation failure.");


 OdbcConnection conn = new OdbcConnection(connectionString);
 OdbcCommand cmd = new OdbcCommand("SELECT PasswordAnswer, IsLockedOut FROM Users " +
    " WHERE Username = ? AND ApplicationName = ?", conn);

 cmd.Parameters.Add("@Username", OdbcType.VarChar, 255).Value = username;
 cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, 255).Value = pApplicationName;

 int rowsAffected = 0;
 string passwordAnswer = "";
 OdbcDataReader reader = null;

 try
 {
  conn.Open();

  reader = cmd.ExecuteReader(CommandBehavior.SingleRow);

  if (reader.HasRows)
  {
   reader.Read();

   if (reader.GetBoolean(1))
    throw new MembershipPasswordException("The supplied user is locked out.");

   passwordAnswer = reader.GetString(0);
  }
  else
  {
   throw new MembershipPasswordException("The supplied user name is not found.");
  }

  if (RequiresQuestionAndAnswer && !CheckPassword(answer, passwordAnswer))
  {
   UpdateFailureCount(username, "passwordAnswer");

   throw new MembershipPasswordException("Incorrect password answer.");
  }

  OdbcCommand updateCmd = new OdbcCommand("UPDATE Users " +
   " SET Password = ?, LastPasswordChangedDate = ?" +
   " WHERE Username = ? AND ApplicationName = ? AND IsLockedOut = False", conn);

  updateCmd.Parameters.Add("@Password", OdbcType.VarChar, 255).Value = EncodePassword(newPassword);
  updateCmd.Parameters.Add("@LastPasswordChangedDate", OdbcType.DateTime).Value = DateTime.Now;
  updateCmd.Parameters.Add("@Username", OdbcType.VarChar, 255).Value = username;
  updateCmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, 255).Value = pApplicationName;

  rowsAffected = updateCmd.ExecuteNonQuery();
 }
 catch (OdbcException e)
 {
  if (WriteExceptionsToEventLog)
  {
   WriteToEventLog(e, "ResetPassword");

   throw new ProviderException(exceptionMessage);
  }
  else
  {
   throw e;
  }
 }
 finally
 {
  if (reader != null) { reader.Close(); }
  conn.Close();
 }

 if (rowsAffected > 0)
 {
  return newPassword;
 }
 else
 {
  throw new MembershipPasswordException("User not found, or user is locked out. Password not Reset.");
 }
}
+1  A: 

I think I've figured it out. With Linq to Entities you can catch EntityException. That would be the equivilent of OdbcException in the above code.

Thanks to anyone who spent time on this.

Irv