So I am writing a custom membership provider for Sitecore and my strategy was to download the source code to the SQLMembershipProvider (which sitecore already uses) and just add my custom logic to it.
One of the core functionalities we wanted was the ability to store a password history and I was working in the ChangePassword function to start.
The first few times I tried my code I had no issue, but now even after computer restarts, attempting to disconnect all users from the database, and refactoring my code so that it only uses a single SQLCommand and one connection I cannot get rid of this error.
I'm including the relevant code from the change password function (I demarked the custom code I added with //my code - start/end). Any ideas?
try { SqlConnectionHolder recentpw_holder = null; SqlDataReader reader = null; SqlCommand tempcmd = null; try { recentpw_holder = SqlConnectionHelper.GetConnection(_sqlConnectionString, true); CheckSchemaVersion(recentpw_holder.Connection); //my code - Start tempcmd = new SqlCommand("SELECT * FROM dbo.PasswordHistory WHERE username='" + username + "' ORDER BY date_created", recentpw_holder.Connection); using (reader = tempcmd.ExecuteReader()) { var passwordlist = new List<string>(); while (reader.Read()) { //get the list of passwords for (int i = 0; i < reader.FieldCount; i++) { passwordlist.Add(reader.GetValue(i).ToString()); } } //if there are more than 10 passwords stored in the database remove the oldest one if (passwordlist.Count > 10) { tempcmd.CommandText = "DELETE * FROM dbo.PasswordHistory" + "WHERE username='" + username + "'" + "AND password='" + passwordlist.First() + "'"; tempcmd.ExecuteNonQuery(); passwordlist.RemoveAt(0); } //check and see if that password has already been used, if so throw an error foreach (var p in passwordlist) { if (p == pass) { throw new ArgumentException("Unable to create password. Password does not meet the history requirements of the domain."); } } } //my code - end tempcmd.CommandText = "dbo.aspnet_Membership_SetPassword"; tempcmd.CommandTimeout = CommandTimeout; tempcmd.CommandType = CommandType.StoredProcedure; tempcmd.Parameters.Add(CreateInputParam("@ApplicationName", SqlDbType.NVarChar, ApplicationName)); tempcmd.Parameters.Add(CreateInputParam("@UserName", SqlDbType.NVarChar, username)); tempcmd.Parameters.Add(CreateInputParam("@NewPassword", SqlDbType.NVarChar, pass)); tempcmd.Parameters.Add(CreateInputParam("@PasswordSalt", SqlDbType.NVarChar, salt)); tempcmd.Parameters.Add(CreateInputParam("@PasswordFormat", SqlDbType.Int, passwordFormat)); tempcmd.Parameters.Add(CreateInputParam("@CurrentTimeUtc", SqlDbType.DateTime, DateTime.UtcNow)); SqlParameter para = new SqlParameter("@ReturnValue", SqlDbType.Int); para.Direction = ParameterDirection.ReturnValue; tempcmd.Parameters.Add(para); tempcmd.ExecuteNonQuery(); //my code pt 2 - start tempcmd.Parameters.Clear(); tempcmd.CommandType = CommandType.Text; tempcmd.CommandText = "INSERT INTO dbo.PasswordHistory " + "(username, password, date_created) " + "VALUES ('" + username + "', '" + pass + "', '" + DateTime.UtcNow + "')"; tempcmd.ExecuteNonQuery(); //my code pt 2 - end status = ( ( para.Value != null ) ? ( ( int )para.Value ) : -1 ); if ( status != 0 ) { string errText = GetExceptionText( status ); if ( IsStatusDueToBadPassword( status ) ) { throw new MembershipPasswordException( errText ); } else { throw new ProviderException( errText ); } } return true; } finally { if (reader != null) { reader.Close(); reader = null; } if( recentpw_holder != null ) { recentpw_holder.Close(); recentpw_holder = null; } } } catch { throw; }