I was adding code, deep in the bowels of the data persistence layer, to update auditing flags when entities where saved. The code received the UserName of the logged in user, looked it up in the User table, and placed the UserId in the CreatedBy or ModifiedBy field as appropriate. If the user could not be found a SecurityException was raised containing the message
User with a login of [user name] cannot be found in the User tableI tested it, everything worked fine, so I committed my changes and moved onto the next task; which was some changes to the Log-In page. Several hours, later I was ready to test my changes to the Log-In page. Whenever I hit the [OK] button, I got a SecurityException with the message
User with a login of [user name] cannot be found in the User tableHaving already forgotten my earlier changes in the persistence layer, I took the message at face value and assumed I had messed up with my changes to the log in page. I then wasted a couple of hours undoing and redoing my work, but to no avail, the exception stubbornly remained.
Eventually I was "smart" enough to follow the exception's stack trace which led me to the code I had changed earlier in data persistence layer. It turned out the membership provider was trying to update the LastLoggedIn date on the user, when my code tried to apply the ModifiedBy flag it couldn't get the logged in user because the log in process wasn't complete yet.
- When you get an exception don't just look at the message, use the stack trace (duh?)
- Make sure you throw appropriate exception types. The fact that I was getting a SecurityException made me think this was a security issue, when in fact it was a data persistence issue. Something like DatabaseRecordNotFoundException would have been better.
- Write exception messages that provide as much contextual information as possible. When writing the message don't assume that the message will be read in the same context as it is thrown. What do I mean by this? The error message I wrote made perfect sense in the context in which I was working, the data persistence layer. But once it escaped the DP layer, and bubbled up to the presentation it made much less sense and sent me off in the wrong direction, wasting time. Imagine how much worse this would be if it occurred some months later in production, and the error message arrived via the help desk with no stack trace.
The error message I finally decided upon read
During a data persistence operation for [entity name] an attempt was made to update the auditing field [CreatedBy/ModifiedBy]. This failed because a user with a login of [user name] cannot be found in the User table