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.
Related
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.
In Java, you explicitly define what exceptions are thrown using the "throws" keyword. That way, anyone calling your method knows what to catch.
Is there something in C#? If not, how do I know what exceptions to catch, or how do I let others know what exceptions to catch?
Also, if I am defining an interface, is there a way to say "methodX() should throw this exception on error"?
There is nothing equivalent in C#: The Trouble with Checked Exceptions
Other than documentation, there is no way to declare an interface to say "methodX() should throw this exception on error".
C#/.net does not have checked Exceptions, they proved to be less useful in large scale systems than first thought. In a lot of projects the time to maintain the check exception specs was a lot greater than the debugging time saved by having them.
Checked Exceptions seem like a good ideal until you have methods that can take delegates or calls into object you pass in. Take a simple case, the Sort() method on a list can’t know what exceptions it will throw, as it does not know what exceptions the Compar() method on the objects being sorted will throw.
So the spec for the exceptions a method may throw must be able to include information on how exceptions are populated from pass in objects and delegates. No one knows how to do this!
However there are tools that you check if you are catching all exceptions – see Exception Hunter by Red Gate. I personally don’t see much value in these tool, however if you like checked exceptions you may find them useful. ==> Looks like Exception Hunter wasn't too useful, so Redgate discontinued Exception Hunter a long while ago:
This feature is not available in C#. You can make proper XML documentation (3 slashes ///) and state what exceptions are being thrown.
This will be picked up by the IntelliSense mechanism and will be visible for the users of the class/method before they use it.
C# does not support this. (Not that I know anyway).
What you can do is use Xml Comments so that while calling you methods this data will be shown by intellisense.
As far as I'm aware there is no throws declaration in C# you can document your method indicating that it throws an exception but no forced error handling.
C# doesn't support checked exceptions. The language designers consider checked exceptions in the way java uses them a bad idea.
Some workarounds
Let me cite this medium article: It's almost 2020 and yet... Checked exceptions are still a thing
Among the many reasons why it's a bad idea, putting the checked exceptions in the contract (interfaces):
makes it impossible to change the implementation of an interface with a different one which throws different exceptions
exposes implementation details
a change of the checked exceptions of an API interface, makes it necessary to change the whole chain of interfaces in the call stack
For example, imagine that you are implementing a repository based on SQL Server, so you expose all kind of SQL Server specific exceptions. Then you want to move it to MySQL or Cosmos BD. Of course:
the implementation can't be changed to a new one that need to throw different exceptions. Also related to this, if you have different implementations of the storage, you can't just change them by configuration, but you need to have different compilations of the code for each storage backend
this is the explanation for 1: as the interface showed the implementation details (SQL Server exceptions) know you can't just change it
if you need to make the change, prepare to change the interface at all levels, since the API that uses the database up to the lates consumer in the call stack chain.
The articles cited above includes pointers to many explanations to discourage the use of checked exceptions, included this by the creator of C#: The trouble with checked exceptions
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.
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..