views:

289

answers:

9

According to the .NET Framework General Reference: Error Raising and Handling Guidelines exceptions should not be thrown during 'normal' operations. Is invalid user input to a web form, say the user enters a duplicate name, considered normal? !! IMPORTANT !!: I'm sure we pretty much all have an opinion on this, please include a reference to a reliable source.

EDIT:

A little more background: I'm questioning the approch to model validation advocated by a book I'm reading. The book is suggesting that you throw a custom exception from a repository when provided with invalid data to save. Now, this seems to me to violate MS guidlines because you are using exceptions as flow control...unless recieving invalid data is consider outside of 'normal' operation. I just want to see if there is any further guidance from a reliable source to resolve this.

+10  A: 

Generally speaking, invalid or ill-formed input is not consider 'exceptional' and should be handled using something other than exceptions. But note that this is a guideline - there may well be situations where using exceptions to handle the problem would result in better code.

Michael Burr
A: 

Code Complete by Steve McConnell provides a check-list for Defensive Programming that is really good. Under the exceptions topic he includes:

  • Does your project have standards (those trump all else)
  • Are there alternatives?
  • Can you handle it appropriately internally to the method?

My feeling is Defensive Programming should always be managed by the method taking in the data. So, throwing an exception would not be appropriate.

There are always mitigating circumstances, of course.

MarkPowell
+2  A: 

an exception is something that is exceptional--that is why they are called exceptions. Bad user input is not an exception, as a general rule, and should be handled gracefully with some type of notification to said user. Also, lets not forget that exceptions really kill the performance of your code.

http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx http://msdn.microsoft.com/en-us/magazine/dd419661.aspx

Muad'Dib
Exactly how performant should your code be in UI-driven events? Worrying about the performance of exceptions is a waste of time unless you have identified it as a cause of badly performing code.
Will
+5  A: 

An invalid user input is an EXPECTED situation. You expect it to happen same often like valid input. When so, throwing exceptions might be too much.

On the other hand, you may throw custom exceptions and catch them internally if you prefer this code style for some reasons. But an invalid user input should not throw that type of exception that would stop your application completely.

Developer Art
Assuming that the first check of the data is in the UI, what happens when the UI validation does not occur or becomes outdated and is at odds with a deeper implementation (i.e. database constraints, domain logic, etc.)? Does a conflict in logic merit being exceptional?
joseph.ferris
The UI would not pass execution to BL until the input is okay, BL would check again and return the validation summary without raising an exception, database integrity is the last line of defense and there it should already raise an exception because the fact that an error got though to the database indicates that something is deeply wrong.
Developer Art
+1  A: 

If you are explicitly validating user input against certain criteria, and plan on taking action based on the outcome of that validation then you will find it far easier if you don't throw exceptions.

Kragen
+3  A: 

Here's how you do it:

On the database side, you throw if you try to create a new user record with a duplicate name. Its an exceptional situation and you can't do anything about it on the database side. You also provide methods for checking the availability of user names.

On the UI side, you allow the user to select a name, then check its availability. Its the responsibility of the UI side to interact with the user and tell them to choose another name. With the ability to check the validity of the name, the UI should never pass in a duplicate name... unless something exceptional has happened.


I agree with the book in this case. Your database is the lowest level of your application and shouldn't have too much business logic coded in it (if A happens, then do B, unless C, then D). That doesn't mean you can't provide useful methods within your data layer that you can use to avoid exceptions.

Will
That is very much the reason behind the way we have implemented. The "general rule" is that the closer to the UI that validation occurs, the lighter it is. We do have validation on multiple levels, with the ultimate goal of preventing more expensive discovery of bad data (i.e. a SqlException). In our DDD approach, we strictly enforce the validity of the object, with the "something exceptional" being that the data was either not validated or the validation rules are at odds with implementation.
joseph.ferris
+1  A: 

Generally no, but I can think of one exception to the rule that I have personally encountered.

We require that our domain objects are valid at all times. If an attempt is made to create or pass bad data, we do thrown an exception from the domain object. In this case, though, it is an "exceptional circumstance". Why? The logic is that bad data should never make it into the domain. Somewhere along that call stack is a place where invalid data was able to be entered into the system - whether it was through a miscalculation, bad data from the underlying data source, or from user input.

Another, ancillary reason we do this, is that the domain objects and their rules are encapsulated within a physically separated assembly. By doing this, we make sure that we provide as much information to the caller, as possible. Because of the implications of what is happening, the assumption is made that the caller will log this so that there is visibility into what truly is an issue - that of not validating the data.

So, in the case where you are looking to see if the data has not been validated or that the rules to validate themselves are at odds with your data persistence methods/functionality, I think that it is perfectly valid to throw. In all other cases, I tend to avoid throwing for invalid input.

joseph.ferris
A: 

I agree with other answer-ers that bad input is expected, and should not be handled with an exception. However, if you discover malicious input (sql injection attempt or something like that), then an exception might be appropriate.

Ray
A: 

I have heard and read that good OO practices would not throw an exception for user input. However, this logic does make me scratch my head a bit too. Think of the history here. Back in C programming, I might write a function such as:

int validateUserInfo(struct info) { //... }

The Caller would do something like: int errorCode = validateUserInfo(info); if(errorCode != 0) handleError(errorcode);

As far as I can remember, exception handling was written to get away from returning error conditions as a return value for methods such as shown above. Yet, if I dont use exception handling for validating user info, am I not back to returning some condition about bad data that causes me to have an if statement to check for invalid data to change my "successful" flow of execution?

Now it seems like I have to check for return values and wrap in try/catch. The validateUserInfo method in a C++/C#/Java class could throw an exception for a "exceptional error" and return "bad data" validation errors as a return value or some other mechanism. Isnt that making the code more complex for the sake of some "OO Rule"?

Of course an OO purist will come back with some alternative such that I dont have to actually return the "bad data" validation error in an attempt to nullify this scenario, but the fact is that somewhere someone will be writing code to check for validation error as well as writing a try/catch block for exceptions.

If exception handling is slow, then the compiler developers should fix it to make it faster. That shouldnt be a reason for avoiding exceptions.

MattFromGA