First of all, you should copy the reference of action
delegate instance before invoking it to prevent threading issues, like this:
private void ExecutionAction(Action action)
{
var handler = action;
if (handler == null)
{
return;
}
try
{
handler();
}
catch (System.Data.SqlTypes.SqlTypeException e)
{
MessagingService.ShowErrorMessage(e.Message);
}
catch (System.Data.SqlClient.SqlException e)
{
MessagingService.ShowErrorMessage(e.Message);
}
}
Secondly, you shouldn't be catching NullReferenceException
s. NREs almost always indicate a programming bug and it is better to fail fast instead of showing an error message without rethrowing it.
User input sucks. You can't trust those users to get anything right, and so you've got to handle all kinds of special cases that make your life difficult. Having said that, we can minimize the difficulty with general principles.
Validate early, not often
Check input for validity as soon as it read into your program. If you read in a string that should be a number, convert it into a number right away and complain to the user if it isn't a number. Any rogue data you don't verify at input will make its way into the rest of the program and produce bugs.
Now, you can't always do this. There will be cases where you can't verify the correct properties right away, and you'll have to verify them during later processing. But you want as much verification to happen as early as possible so that you have your special cases around input logic centralized to one location as much as possible.
Use Schemas
Let's consider a function that parses some json.
def parse_student(text):
try:
data = json.parse(text)
except ValueError as error:
raise ParseError(error)
if not isinstance(data, dict):
raise ParseError("Expected an object!")
try:
name = data['name']
except KeyError:
raise ParseError('Expected a name')
if not isinstance(name, dict):
raise ParseError("Expected an object for name")
try:
first = name['first']
except KeyError:
raise ParseError("Expected a first name")
if not isinstance(first, basestring):
raise ParseError("Expected first name to be a string")
if first == '':
raise ParseError("Expected non-empty first name")
That was a lot of work just to extract the first name, let alone any other attributes. We can make this a lot better if we can use a json-schema. See: http://json-schema.org/.
I can describe what my student object looks like:
{
"type": "object",
"properties": {
"name": {
"type": "object",
"properties": {
"first" : {
"type" : "string"
}
},
"required": "first"
},
}
"required": ["name"]
}
When I parse I then do something like:
def parse_student(text):
try:
data = json.parse(text)
except ValueError as error:
raise ParseError(error)
try:
validate(data, STUDENT_SCHEMA)
except ValidationError as error:
raise ParseError(error)
first = data['name']['first']
Checking against the schema verifies must of the structure that I need. If the user input failing the schema, the schema validator will produce a nice error message explaining exactly what was wrong. It will do so far more consistently and correctly then if I wrote the checking code by hand. Once the validation has been passed, I can just grab data out of the json object, because I know that it will have the correct structure.
Now, you probably aren't parsing JSON. But you may find that you can do something similar for your format that lets you reuse the basic validation logic across the different pieces of information that you fetch.
Best Answer
I believe that logs and exceptions are for developers, therefore they should be in the best language to suit the development team. This may be their native language, however it may be (and judging from the comments often is) English. This allows developers to work in a language they are familiar with and not have to translate from French, Spanish, or Chinese to work a problem.
However, your users may not all be English speakers.
To give the best user experience you may well want to localise any error messages you feel you need to display to the user.
You could do that in a number of ways:
Or (and probably the way I'd do it):
My suspicion is that the author of the article you linked assumes you're going to be displaying ex.ErrorMessage directly to end users. I wouldn't do this, ex.ErrorMessage often contains technical (and sometimes even sensitive) details and should therefore not be shown. It also makes you THINK about what you are presenting to the user. Catching, logging, and apologising gets you into that habit.
In summary. I'd make sure your exceptions and logs are as easy and accessible for your developers as possible. But make sure that your website (and error messages displayed) as as clear for your users as possible.