Let me give you an example. I have the following web method inside my aspx.cs file which I use for AJAX calls:
[WebMethod]
public static ResponseMessage GetNextQuestion(string quizGuid)
{
using (DbEntities db = new DbEntities())
{
Quiz theQuiz = Quiz.Get(db, DataValidationHelper.GetGuid(quizGuid));
try
{
Question nextQuestion = QuizHelper.GetNextQuestion(db, theQuiz);
return new ResponseMessage() { Status = "Success", NextQuestion = new NextQuestionResponse(nextQuestion, theQuiz) };
}
catch (QuizNotFoundException)
{
return new ResponseMessage() { Status = "QuizNotFound" };
}
catch (QuizInvalidException)
{
return new ResponseMessage() { Status = "QuizInvalid" };
}
catch (QuizOverException)
{
return new ResponseMessage() { Status = "QuizOver" };
}
catch (QuestionTimedOutException)
{
return new ResponseMessage() { Status = "QuestionTimedOut" };
}
catch (Exception ex)
{
return new ResponseMessage() { Status = "Error", ErrorMessage = ex.Message };
}
}
}
The QuizHelper.GetNextQuestion
method generates a new question from the database and in some specific cases throws the following exceptions:
QuizNotFoundException
: When a quiz with the givenquizGuid
is not found in the database.QuizInvalidException
: Thrown for security purposes, for example when someone tries to hack HTTP requests.QuizOverException
: Every quiz has 10 questions and when the user tries to get 11th question using theQuizHelper.GetNextQuestion
method, this exception is thrown.QuestionTimedOutException
: You have to answer a question within a given time. If you don't, this exception is thrown.Exception
: All other exceptions are grouped under this for the sole purpose of informing the user that an error has occured, for UX purposes.
Then inside the Javascript file, the ResponseMessage.Status
is checked and corresponding action is taken.
I know that using exceptions as they are used in this code to control the flow is bad but making it this way is more intuitive and is much simpler. Not to mention the fact that the code is easier to understand for an outsider.
I am not sure how this code could be rewritten in the "right way" without exceptions but at the same time conserving its simplicity.
Am I missing something, any ideas?
UPDATE: Some answers propose using an Enum to return the status of the operation but I have lots of operations and they all may result in different scenarios (i.e. I cannot use the same Enum for all operations). In this case creating one Enum per operation does not feel to be the right way to go. Any improvements over this model?