Consider a C# GUI application which uses a FileStream to read a file, chosen by the user through an "Open File" dialog.
In case the read fails with one of the exceptions, what is the correct way to report the failure to the user, in an user-friendly manner?
Should I invent my own message for each of those exceptions, or is there a way of obtaining a localized, user-friendly message that I could present verbatim to the user?
Edit
I'm asking whether .NET itself is able to provide me with a descriptive string that I can present (and which would be consistent with other .NET programs). I know that I can roll up my own, but I'd like to avoid that if there's a standard alternative.
You can have a set of localizable user exceptions with one of them being say FileUploadError. You can put a localized general information there. Throwing a few technical details might be a bit challenging, as it can be quite hard to get the right balance between technical details and a simple step that a user needs to take to fix an error.
My suggestion would be:
Have one user level FileUploadErrorException
Have a details property in it
Depending on the actual exception, suggest a user to try a few things
If you are catching an exception thrown by one of the .Net framework's File classes, then it is likely that the contents of the exception's .Message property will already be localized. The .Message property is supposed to contain localized, human readable text. How 'friendly' it is depends, I guess, but it might contain something you can embed within a more general and friendly paragraph.
Assuming you might write some method AlertUserWithMessage() to display the error to the user, this might be useful:
try
{
fileStream.Read(...); // or some other operation
}
catch(Exception e)
{
AlertUserWithMessage(e.Message);
}
If you want to include additional information that might be helpful to a support person diagnosing the problem, then you can also get the stack trace as a string from the exception.
try
{
fileStream.Read(...); // or some other operation
}
catch(Exception e)
{
AlertUserWithMessageAndStackTrace(e.Message, e.StackTrace);
}
Exception messages are by nature technical and describe what went wrong (at implementation level), as opposed to how to solve an end user's problem. On the other hand the intent of an error message presented to the user is to explain what failed and what action to take to remedy the problem. Exceptions messages and end-user error messages don't have the same purpose and aren't written for the same audience.
So for decent user experience, it is much better to map these exceptions to localized user-friendly advice on how to get around the problem. Sure, for technical users it could be nice to have some diagnostic feature that could give details of the exception (in which case having exception messages in English doesn't matter that much--English is really the world's technical language), or just point them to a log with all the details. But just throwing an exception message, even localized, at an end user is likely to baffle them.
For this reason I don't think localizing exception messages is much use. It's true that the .NET framework has localized exception messages for major languages, but I think that's more because there are developers who use these languages as their base language and do not necessarily have a good command of English. So the audience of these localized exception messages is still developers, not end users of a software product built in .NET.
Related
I need to make a short premise: I am a software architect with more than 20 years of experience, not a junior asking directions. This is not to say "I know it all" (quite the contrary in fact) but just to give context and state that I have come across a legitimate doubt about something I thought was common knowledge and best practice and have done so for all this time.
I am working on different projects for different clients. I always check method's parameters for not being null and for other non valid states. A common precondition check you can find in my code is:
if (param == null) { throw new ArgumentNullException(nameof(param)); }
or
this.myField = myParam ?? throw new ArgumentNullException(nameof(myParam));
Also bear in mind that I use exceptions sparingly, I do not do user input validation with exceptions, I just use them to check and/or signal invalid states in the code, thus programming errors. It's extremely rare to find a try/catch block in my code at all.
One of my clients just asked me, without much margin to debate, to replace any similar occurrence with the use of custom exceptions. Meaning I am to define a CustomerNameArgumentNullException, CustomerNameFileNotFoundException, etc. and use those wherever I would use a standard exception.
Now I will comply, I have no right to debate the client request, but their lead programmer was pretty strong about this point on how this is the right way to go, that using default exceptions makes code less readable and also that custom exceptions make more easy to see what-is-what in Azure Application Insights. I tried to point out that he has the fully qualified name of the method that raised the exception so he can know which program, in which assembly and namespace and such but again, there was not much room to debate and it was not my place to do so.
So I've been wondering if he's actually right and I've been doing exceptions wrong all this time. If anyone has some more insight and/or some material I can read about that supports this theory.
Thanks.
While normally I'd suggest that a question like this should be closed as opinion-based, in this case there's really clear guidance from Microsoft:
Use the predefined .NET exception types
Introduce a new exception class only when a predefined one doesn't apply. For example:
Throw an InvalidOperationException exception if a property set or method call is not appropriate given the object's current state.
Throw an ArgumentException exception or one of the predefined classes that derive from ArgumentException if invalid parameters are passed.
In other words, your customer is asking you to go against guidance from the platform authors.
You may not be able to change the customer's mind to follow the guidance, but you can be confident that your approach is the recommended one, and their approach goes against that.
Following conventions like this is particularly important in Open Source projects - it's one thing to decide that you'll have your own conventions when only your team will work with the code, but if an application uses 10 different Open Source libraries, each of which has decided to create its own conventions, that's a nightmare.
There are two sides of the coin. Sure MS recommends this
Using custom exceptions gives you some advantages and disadvantages.
Advantages:
Abstraction
You can log telemetry data before you raise an exception. If not for custom exceptions, you'd have to catch an exception, log data and re-throw.
Customizing exception and error handling as needed by the app/services, etc
Disadvantages:
Telemetry data will have no stack trace if you are throwing custom exceptions.
Code maintenance and rigorous testing
There are various other things that come into picture, but catching an exception, logging metrics and then re-throwing (to preserve stack trace) the same exception is expensive.
Just my thoughts.
Very often in .NET methods throw generic errors like e.g.
int.Parse("test")
throws an exception with this message:
Input string was not in a correct format.
Now it would save a lot of trouble for many people if it just had the parameter value to help debug things easier:
Input string "test" was not in a correct format.
This seems like a natural and easy thing to have, yet .NET does not do it in many places like e.g. parsing. Is there is any reason or conceptual problem with doing that or is it just a "missing feature"?
I suspect that the reason is primarily for security reasons. Some concerns with displaying/rendering the text to be parsed in the message returned are (but not limited to)
The text to be parsed may be very long. This is would be problematic from a memory usage and display perspective not to mention developer's habits of logging exception messages (not unreasonably).
The text may contain characters that mess with the formatting (e.g., tab, LF, CR, etc.)
The text may contain sensitive data. On this point, it's worth nothing that most developers, at least starting out, generally log or display error messages at an exception level by default. Not including the text here means there's no unintended data leak to catch the unwary.
It's conceivable (though unlikely) that an exploit could be found whereby a malformed piece of text could have a nasty unintended side effect.
Additionally, the value being parsed is being supplied by the caller which leaves them the option of deciding if it's best to log the content or not - it's not int.Parse()'s place to return the value in the exception message.
All in all, displaying a concise message without the originally supplied value is a judicious decision on part of MS to save us from ourselves as well as follow security best practices.
I am wanting to discover what possible standard .net exceptions can cause stack traces to include sensitive information.
It is my understanding (correct me if I am wrong) that if a SQL connection fails then the exception message created will include the connection string which in turn might include the user name and passowrd (if not using integrated security).
We log the exception message out to log files that might be read by people that should not see that information.
What other exceptions can include information such as this that you know of?
The application in question uses Web, WCF and DB (SQL Server).
Thanks
Personally I don't think that you are going around this the right way. Trying to identify the number of exceptions that could have information in them is going to expose you to risk more than likely as one item will get missed, it just happens.
I would switch focus a bit and try to identify where you can log them to be a secure location.
Another unknown to think about here is that you could have a message created by a developer that contained sensitive information, and identifying those would be very hard.
I'm working on a project and I'm just starting to do all the work necessary to globalize the application. One thing that comes up quite often is whether to globalize the exception messages, but ensuring that string.Format uses CultureInfo.CurrentCulture instead of CultureInfo.InvariantCulture. Additionally this would mean that exception messages would be stored in resource files that can be marked as culture-specific.
So the question is, should exception messages be globalized or should be be left in either the InvariantCulture or the author's country; in my case en-US.
Exception messages should rarely be displayed directly to the user. You need to think of the consumer for each string. Obviously pieces of text in the user interface need internationalizing, but if an exception message is only going to be seen by support (or is going to be visible to the user and then emailed to support when they click a button) then where's the benefit of translating it?
If you go too far, you could not only waste time and effort (and i18n can take a lot of effort) but you'll also make your support life harder as well. You really don't want to have to read log files written in a foreign language and translate them back to your native tongue.
It makes sense for Microsoft to internationalize their exception messages, because they will be read by developers from all over the world - but unless you're multinational with developers in multiple countries who don't share a common language, I wouldn't translate message which are really meant for dev/support.
typically, I don't.
Globalize strings that may be seen by a user, and you don't let your exception messages percolate up to the UI, right?
Right? :)
If you are going to be the one to deal with the exceptions, then either leave them in a language you can understand, or give them codes so you can look them up in your native language.
I assume by globalize, you mean i18n compliant which is usually called internationalize. Yes, internationalize all visible parts of the GUI, including diagnostic messages. The log file, which is where developers should go to get the real information such as the stack trace, should not be internationalized.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
In writing the code that throws the exception I asked about here, I came to the end of my message, and paused at the punctuation. I realized that nearly every exception message I've ever thrown probably has a ! somewhere.
throw new InvalidOperationException("I'm not configured correctly!");
throw new ArgumentNullException("You passed a null!");
throw new StupidUserException("You can't divide by 0! What the hell were you THINKING??? DUMMY!!!!!");
What tone do you take when writing exception messages? When going through logs, do you find any certain style of message actually helps more than another?
A conversational tone in system messages makes the software look unprofessional and sloppy. Exclamation points, insults, and slang don't really have a place in polished exception messages.
Also, I tend to use different styles in Java for runtime exceptions and checked exceptions, since runtime exceptions are addressed to the programmer that made the mistake. Since runtime exceptions might be displayed to end users, I still "keep it clean," but they can be a little more terse and cryptic. Checked exception messages should be more helpful, since it may be that the user can fix the problem if you describe it (e.g., file not found, disk full, no route to host, etc.).
One thing that is helpful, in the absence of a specific field on the exception for the information, is the offending data:
throw new IndexOutOfBoundsException("offset < 0: " + off);
Just be matter of fact. Include all the information you're likely to need when debugging, but no more than that.
The only time I'd include an exclamation mark in an exception message is if it indicates that something really, really bizarre has happened. Most errors aren't really bizarre, just the product of an incorrect environment, user error, or a simple programming mistake.
I try to mirror the tone, grammar and punctuation style of the framework against which I'm coding. You never know when one of these messages might actually make it out in front of a client or user, so I keep everything professional, non-judgmental and specific enough for troubleshooting -- without being so specific as to give away any security issues in the code.
I avoid exclamation marks in all strings (UI and exception) like the plague, except (ocasionally) in my unit tests.
Taking responsibility, even when it really was the user's fault, is the best option I've seen.
Things along the lines of "I can't find the file you wanted, would you check to see I have it correctly?" or "Something went wrong. Dunno what, but the only way I can get fixed is by stopping. Please restart me."
Concise, detailed and little redundant information (i.e. ArgumentNullException obviously involved a null).
But here's the best i've read for a while, first answer to this.
I wouldn't use exclamation marks too much. They express too much, think about the fact that "No disk in drive!" can be read as "No disk in drive you crazy user." ;)
I think that it's wise to throw exceptions that contain internationalized text. You never know who will use your code, catch your exception and display the text to the user.
So that would be:
throw new MagicalException(getText("magical.exception.text"));
I also recommend wrapping the underlying exception (if you have one) when throwing it. It really helps debugging.
Don't think that runtime exceptions won't be seen by the user. If you are logging to a file appender some curious user might just open the log and peek into your dirty secrets.
I find the most helpful messages provide:
A consistent format that makes it easy to understand what they're telling you.
A time stamp, so you can get a feel for the dynamics of your program.
A terse summary of the error. If you provide tech support, add an error code for quick identification.
An explanation of what went wrong, differentiating between an invalid user input and a coding error.
Detailed information, including the line of code or values involved.
And most important:
They tell the user how to fix the problem.
Example: Error 203 (Timeout) in commit.c line 42:
Unable to save salary data for user 'Linus' to database at '10.10.1.21'
after 1500ms. Verify database address and login credentials.
One of the hardest lessons to learn is that your users are far less interested in the internals of your code than they are in getting their jobs done. Make it as easy as possible for them to do their jobs, and you've added tremendous value to your software.
I tend to work my exception messages into the exception themselves. E.g. a file_not_found should say "file not found". Specific data should only be included if the user can't figure it out; in this case, the user knows the filename, so I don't add that data. Formatting can be done by whatever outputs the information if necessary, so I try to make them as friendly to reformatting as possible.
Polite, terse, simple, specific. Often, including state values in message is helpful.