When throwing exceptions, I often pass in a formatted string that exposes details about the problem that has occurred. I always specify a formatting provider if possible (which is good practice because otherwise you may forget to decide which culture is appropriate and as the default is the current culture, that can lead to many bugs).
Here's an example:
throw new InvalidOperationException(
string.Format(
CultureInfo.CurrentCulture,
"{0} is a bad number.",
number));
I'm tempted to use CurrentCulture, as shown above, because exception messages are targeted at human beings (ofcourse, code should never act on the exception message itself). The message will be formatted using the client's culture so whenever I need to display it to my client, it looks nice.
However, besides displaying messages to users, exceptions may be logged to a log file as well. I've seen many messages sit in my log files, with all kinds of cultures used for formatting them. Pretty ugly! In this case, InvariantCulture would be more appropriate or perhaps the culture of the server that is hosting the log file.
The point here is that when formatting an exception, you just never know your audience so it seems impossible to decide which culture to use when formatting. It would be great to be able to postpone the formatting to the point at which the exception is caught but that would go way beyond the way exceptions are implemented in .NET.
So what are your thoughts on this?
Since your exception message is in English, I would stick to the invariant culture. Why should you mix English text with non-English number formats?
If you however go as far as to localize the exception messages (like the .NET framework does), you would want to use the culture of the selected resource assembly. This makes sure that number formats and language will match, even if there is no localization available (i.e. it falls back to English).
However in my understanding exception messages are primarily meant for developers. Therefore I wouldn't consider localizing them, unless it is a big project with developers from all over the world. If you can't handle an exception, you should catch it and provide the user some error message that is appropriate in the given context (and which might or might not be as precise as the exception message).
Providing them with the exception message itself could (especially for web servers) expose details about the server software, which could be used maliciously. I think it is better to log the exception and provide the user with a (localized) error message and some data that makes it possible to associate the log event (most likely non-localized, invariant culture) with their feedback.
WCF for example will not report back exception details to a user, unless being explicitly configured this way. See IncludeExceptionDetailInFaults configuration setting and the "caution" block there.
IMHO you may use the "Data" property of the exception class.
This way, you may store in the "Message" property the invariant message you want to log.
And you could add to the "Data" collection a keypair value with Key = "UIMessage" and Value = your ui message properly formatted to the user culture (and may be your message translated according to the right culture).
In your exception handler, then you may just have to choose between the Message property and you Data pair in order to log or display the proper message.
Related
I don't really know the best way to handle exception in an multi-language application.
Where should I handle the translation of the error message (Exception.Message)?
Shall I translate the message in the ctor as soon as I throw the exception?
throw new MyException("Error message", Resource.MyException_TranslatedMessage);
Or do I throw the exception and I use a home made helper that will find the error message using the type of the exception in the logic of the View?
try
{
//...
}
catch(Exception ex)
{
myLabel.Text = new ExceptionTranslator(ex).Translate();
}
Or, does Microsoft offer a tool or a mechanism to do that?
In a word: what are the good practices to handle exception messages translation?
Most exceptions are there for technical purposes, unless your operations and maintenance crew are also located in different countries, those exceptions should simply have messages in the language of the people who write and maintain the application.
The .NET framework contains localized exception messages. For me as a developer, that's very annoying, since the exception messages in my local language (Dutch) don't mean as much as the original English exception messages. However, it seems reasonable for Microsoft to localize those framework exception messages, since their target audience can be located anywhere.
Some types of exceptions however, are explicitly thrown to be displayed to the user. These are your ValidationException or BusinessLayerException. Their clear contract is to be displayed to the user. Of course you should localize those exception messages, but instead of translating them, it's often much better and easier to pull the exception message from a localized resource when throwing the exception:
throw new ValidationException(Resources.InvalidUserName);
Much better to only translate it when it needs to be displayed, IMHO.
This applies to any localisable string, not just error messages.
Ideally, the logic of the code shouldn't care about the content - or language - of the message, it's only interested in the type of the exception. It's only the presentation layer that (might) need to display it in the local language.
The external code should not translate messages
throw new MyException("Error message", Resource.MyException_TranslatedMessage);
This is best solution in my mind
I've noticed that most exception messages don't include instance-specific details like the value that caused the exception. They generally only tell you the "category" of the error.
For example, when attempting to serialize an object with a 3rd. party library, I got a MissingMethodException with message:
"No parameterless constructor defined for this object."
In many cases this is enough, but often (typically during development) a message like
"No parameterless constructor defined for this object of type 'Foo'."
can save a lot of time by directing you straight to the cause of the error.
InvalidArgumentException is another example: it usually tells you the name of the argument but not its value.
This seems to be the case for most framework-raised exceptions, but also for 3rd party libraries.
Is this done on purpose?
Is there a security implication in exposing an internal state like the "faulty" value of a variable?
Two reasons I can think of:
Firstly, maybe the parameter that threw the exception was a value that was a processed form of the one that was passed to the public interface. The value may not make sense without the expense of catching to rethrow a different exception that is going to be the same in most regards anyway.
Secondly, and more importantly, is that there can indeed be a security risk, that can be very hard to second-guess (if I'm writing a general-purpose container, I don't know what contexts it will be used in). We don't want "Credit-Card: 5555444455554444" appearing in an error message if we can help it.
Ultimately, just what debug information is most useful will vary according to the error anyway. If the type, method and (when possible) file and line number isn't enough, it's time to write some debug code that traps just what you do want to know, rather than complaining that it isn't already trapped when next time you might want yet different information (field state of instances can be just as likely to be useful as parameters).
InvalidArgumentException and (per #Ian Nelson) "Key not found in dictionary" both share something in common - there's no guarantee that the framework would be able to find a suitable value to show you - if the key/argument is of any user defined type, and ToString() hasn't been overridden, then you would just get the type name - it's not going to add a lot of value.
Exceptions are mostly meant for a program to consume. Most programs wouldn't know what to do with information about the instance.
The Message property is aimed at human consumption. Other than in a debugging scenario, humans won't know what to make of Foo.
Many exception mechanisms try to serve a hodgepodge of orthogonal purposes by passing a single exception-derived object:
Letting the caller know that various specific things have happened, or that various specific problems exist.
Determining when the exceptional condition is "resolved" so that normal program flow can continue.
Providing an indication of what to tell the user of the program
Providing information which could be logged to allow the owners of a system to identify problems, when a secure log is available
Providing information which could be logged to allow the owners of a system to identify problems, but which would not pose a security risk even if secure logging is not available.
Unfortunately, I'm unaware of any exception mechanism in widespread use which can actually accomplish all five of the above, well.
I'm writing an XML code editor and I want to display syntax errors in the user interface. Because my code editor is strongly constrained to a particular problem domain and audience, I want to rewrite certain XMLException messages to be more meaningful for users. For instance, an exception message like this:
'"' is an unexpected token. The
expected token is '='. Line 30,
position 35
.. is very technical and not very informative to my audience. Instead, I'd like to rewrite it and other messages to something else. For completeness' sake that means I need to build up a dictionary of existing messages mapped to the new message I would like to display instead. To accomplish that I'm going to need a list of all possible messages XMLException can contain.
Is there such a list somewhere? Or can I find out the possible messages through inspection of objects in C#?
Edit: specifically, I am using XmlDocument.LoadXml to parse a string into an XmlDocument, and that method throws an XmlException when there are syntax errors. So specifically, my question is where I can find a list of messages applied to XmlException by XmlDocument.LoadXml. The discussion about there potentially being a limitless variation of actual strings in the Message property of XmlException is moot.
Edit 2: More specifically, I'm not looking for advice as to whether I should be attempting this; I'm just looking for any clues to a way to obtain the various messages. Ben's answer is a step in the right direction. Does anyone know of another way?
Technically there is no such thing, any class that throws an XmlException can set the message to any string. Really it depends on which classes you are using, and how they handle exceptions. It is perfectly possible you may be using a class that includes context specific information in the message, e.g. info about some xml node or attribute that is malformed. In that case the number of unqiue message strings could be infinite depending on the XML that was being processed. It is equally possible that a particular class does not work in this way and has a finite number of messages that occur under specific circumstances. Perhaps a better aproach would be to use try/catch blocks in specific parts of your code, where you understand the processing that is taking place and provide more generic error messages based on what is happening. E.g. in your example you could simply look at the line and character number and produce an error along the lines of "Error processing xml file LineX CharacterY" or even something as general as "error processing file".
Edit:
Further to your edit i think you will have trouble doing what you require. Essentially you are trying to change a text string to another text string based on certain keywords that may be in the string. This is likely to be messy and inconsistent. If you really want to do it i would advise using something like Redgate .net Reflector to reflect out the loadXML method and dig through the code to see how it handles different kinds of syntax errors in the XML and what kind of messages it generates based on what kind of errors it finds. This is likely to be time consuming and dificult. If you want to hide the technical errors but still provide useful info to the user then i would still recomend ignoring the error message and simply pointing the user to the location of the problem in the file.
Just my opinion, but ... spelunking the error messages and altering them before displaying them to the user seems like a really misguided idea.
First, The messages are different for each international language. Even if you could collect them for English, and you're willing to pay the cost, they'll be different for other languages.
Second, even if you are dealing with a single language, there's no way to be sure that an external package hasn't injected a novel XmlException into the scope of LoadXml.
Last, the list of messages is not stable. It may change from release to release.
A better idea is to just emit an appropriate message from your own app, and optionally display -- maybe upon demand -- the original error message contained in the XmlException.
This title begs for more explanation.
Basically, I'm rolling an API that wraps a web service in a nice heirarchical model. This model exposes things in the form:
var obj = MyRemoteResource.GetForId(1234, SourceEnum.ThatSource);
ApiConsumerMethod(obj.SomeProperty); //SomeProperty is lazily loaded, and often exposes such lazily loaded properties itself
... etc ...
Where many different RemoteResources* (each with many properties exist). There's really aggresive cacheing going on, and request throttling to prevent inadvertantly DOS'ing the servers (and getting the IP of the caller banned).
I've got all this code working, but I'm not doing much in the way of error handling at the moment. Basically, if the consumer of an API provides an invalid ID, the web server is down, a connection times out, or any other of a plethora of request layer errors occur an exception just percolates up when a property is accessed.
I consider this far less than ideal.
So my question is, how should I wrap these errors up so that it is convenient for a user of this API to manage them?
Some routes I have considered:
Just wrap all exceptions in some API defined ones, and document them as thrown.
Expose a static ErrorHandler class that allows a user to register notification callbacks for specific errors; falling back to the above behavior when no registration has been made for specific errors.**
Null properties on error, and set a LastErrorCode.
Each of these approachs have strengths and weaknesses. I'd appreciate opinons on them, as well as alternatives I haven't thought of.
If it impacts the discussion at all, the platform class throwing these exceptions is WebClient. Furthermore, usage of WebClient is sufficiently abstract that it could easily be replaced with some other download scheme if needed.
*Which is to say, many different classes
**This would be... wierd. But it maps to the global nature of the failure. This is my least favorite idea thus far.
I wouldn't implement fancy error technologies (like events and stuff like this). It's not easy to judge where and how to use exceptions, but this is no reason to implements other stuff.
When you request an object by an id which doesn't exist, what do you have to tell the caller about this? If you just return null, the client knows that it doesn't exist, there is nothing more to say.
Exceptions force the caller to care about it. So they should only be used where the caller is expected to do something special. Exception can provide the information why something didn't work. But if it is an "error" the user could also ignore, an exception is not the best choice.
There are two common alternatives to exceptions.
Use return values which provide information about the result of an action. For instance, logon could return a LogonResult instead of throwing an exception.
Write two methods, one throwing an exception, and one (Try...) returning a boolean. The caller decides if it wants to ignore the "error" or not.
Personally I believe this is entirely dependent on the context of what your API end-user is trying to do. If this is the case, you should let them decide how to handle erors.
Recently when working with CSV files (very error prone) I used an API that allowed you to define the exception behaviour. You could either ignore the error, replace by some default value/action, or pass them off to an event handler.
I really liked this approach of letting the end user decide how to handle internal exceptions, because unless your API is very specific its difficult to preempt all scenarios.
I prefer to have an exception thrown at me when something bad happens. Exceptions are (for me, anyways) the common way to tell that something went wrong, and i find it more intuitive to catch, than to check a return value for null and check another property to see what went wrong..
Since I can't use Microsoft as an example for best practice since their exception messages are stored in resource files out of necessity, I am forced to ask where should exception messages be stored.
I figure it's probably one of common locations I thought of
Default resource file
Local constant
Class constant
Global exception message class
Inline as string literals
I may get shot (well, downvoted) for this, but why not "where you create the exception"?
throw new InvalidDataException("A wurble can't follow a flurble");
Unless you're going to internationalize the exception messages (which I suggest you don't) do you particularly need them to be constants etc? Where's the benefit?
If your exceptions are strongly typed, you don't need to worry about messages. Messages are for presenting errors to users, and exceptions are for controlling flow in exceptional cases.
throw new InvalidOperationException("The Nacho Ordering system is not responding.");
could become
throw new SystemNotRespondingException("Nacho Ordering");
In the latter case, there's nothing to translate, and therefore no need to worry about localization.
Out of necessity? It's to ease localization. To localize error messages in your applications, it's a great way.
If you are not going to show the exception messages to the user, then you need to keep them separate from the resource strings you do need to translate.
Either use string literals like Jon suggests or create a utility class to hold them if you have a lot of duplicate strings.