Anonymous578167

Hi,

I have a standard ASP.Net web site which makes use of a number of class libraries. These class libraries can obviously raise an exceptionraian exception when things go wrong.

The front end ASP.Net uses resource files in the App_GlobalResources to internationalise the standard text displayed in the browser. However I was wondering is there any best practices for internationalising an exception/error message

I had thought of using a key instead of a message when I throw the exception. When I then catch the exception I could use this key to get the correct message from the resource files e.g.

Resources.MySite.DBConnectionErr.

Anyone know of any better approaches

Thanks.



Re: .NET Base Class Library Exception Message Globalisation Best Practices

Peter Ritchie

Exception text is just that: exceptional. It's not intended as a means of communicating with the user. If would suggest having a last-chance exception handler that catches all unhandled exceptions and displaying a generic, localized message to the user that an error occurred. Optionally, log exceptions somewhere (event log, file, etc.) that support personnel can get from the user, should those details be needed.




Re: .NET Base Class Library Exception Message Globalisation Best Practices

nobugz

FxCop complains with CA1303 when you pass a literal string to an exception constructor. Check this query for possibly useful commentary and advise.





Re: .NET Base Class Library Exception Message Globalisation Best Practices

Peter Ritchie

nobugz wrote:
FxCop complains with CA1303 when you pass a literal string to an exception constructor. Check this query for possibly useful commentary and advise.
In a framework, I can see the benefit of localized exception messages as you're dealing with developers. With a regular application, presenting a translated exception message along with the stack trace in the framework unhandled exception dialog adds no value in my opinion. Translating "An error occurred; please contact customer support" makes for a far nicer user experience (assuming exception details are logged and techs can easily get users to send that info...).

There's actually been some call for an ability turn off CA1303 for exception c'tors for the non-framework developers. I don't know what's being done in that respect; probably nothing until post-Orcas.

Microsoft would be the first to tell you of the suppression abilities in FxCop and Code Analysis and that not all warnings will apply to all projects.






Re: .NET Base Class Library Exception Message Globalisation Best Practices

Anonymous

Thanks for the help so far it's greatly appreciated. Just a few small points to try and get a few issues straight in my own head.

In my application the user will have a project and will be able to assign resources and carry out operations on the project relating to the business domain. Depending on the state of the project some of these operations may not be allowed, and the plan was therefore to log and raise an Exception using an error code as the exception message.

At the presentation level I was planning to use the error code to get the message to display to the user, I do not plan on letting the user see the exception stack trace.

At this point my question would be, what is the best mechanism to provide functionality such as this. I know the obvious answer will probably be disable the operations so the user can only attempt valid operations, this unfortunately isn't an option give the design.




Re: .NET Base Class Library Exception Message Globalisation Best Practices

nobugz

There are two, quite opposing views on how to deal with exceptions properly. One view, sponsored by MSFT, is to treat exceptions that cannot easily be recovered from as fatal errors that should terminate the program. The other, more pragmatic view is that exceptions should be caught by the top level function in the stack and reported to a human, preventing the program from terminating.

The latter is *much* harder to implement as you must make sure that an exception doesn't change the program state. You'll need lots of catch/throw and "finally" handlers to ensure you undid what you started out doing but couldn't finish. This was especially hard to do in the bad old days, leaking a heap block or file handle was very easy to do.

I'm firmly in the view #2 group, most of all because I write applications where a restart isn't a viable cop-out (industrial automation). If you feel confident that you know how to recover from an exception and make your program invariant to the exception, by all means, catch it. You then should provide a good diagnostic to the user that ought to be tuned to the culture. If you're not so sure you can, just let it crash. You're guaranteed to get a phone call from the user, the message only has to make sense to you.

Since you already made exceptions a normal outcome of a user request, you'll need to commit to view #2.





Re: .NET Base Class Library Exception Message Globalisation Best Practices

Peter Ritchie

nobugz wrote:
The other, more pragmatic view is that exceptions should be caught by the top level function in the stack and reported to a human, preventing the program from terminating.
I would consider that less than pragmatic, and more error prone. How can you possibly catch an exception at a top-level and continue running Unless you mean preventing the program from terminating until the user responds (but that's what the framework unhandled exception dialog does).

The generally accepted methods are: only catch exceptions you can handle at that level, and if you don't want exception details displayed to the user have a last-chance exception handler (in a WinForms app this would be a try/catch around Application.Run et al) that displays a sanitized message before exiting. I've seen nothing in terms of guidance that suggest the application should not terminate at that last-chance handler (except for secondary threads, they may not need to cause the application to exit). Principles like this are only clarified by non-Microsoft sources like http://musingmarc.blogspot.com/2005/09/exception-handling-in-net-some-general.html and http://codebetter.com/blogs/karlseguin/archive/2006/04/05/142355.aspx.

I've joined several projects that had the view that exceptions should never cause the application to exit or leak out to the user. In all cases this caused problems (i.e. hiding bugs, circumventing exception's ability to allow code higher-up in the stack to handle exceptions, etc) and spend much time refactoring the code and in some case the entire design because of it.

When you try and avoid having exceptions leak out to the user it's near impossible to decide at what level that should be done and you end up catching them as close to the method/code that throws them--ending up with catch(Exception). This completely circumvents higher/one-level handling abilities and ends up transforming exceptions into return codes (very bad in object-oriented designs because it couples error handling in the wrong place). There are many framework methods that inadvertently throw exceptions for normal flow of control (this is why TryParse was introduced in .NET 2.0)--exception avoidance can end up hiding that normal flow of control.

One of the great features of exceptions is you can catch certain exceptions at one level. For example, if I want to call several methods that might perform database-related logic, I can wrap them in BeginTransaction();try{}catch(SqlException e){} In most circumstances I probably want to simply Rollback the transaction because that's the level where the transaction was created. This is not something I could do if the program is designed not to allow exceptions to terminate the application and leak to the user because many of the methods I may have called wouldn't have let exceptions out. The transaction would have been committed and who knows what data ended up in the database.

As frameworks and libraries evolve, new exceptions are added; if you're always ensuring exceptions don't leak out (resulting in catch(Exception)) you inadvertently swallow those new exceptions, hiding them from higher-level code that could have handled it.

If you can "handle" an exception (that is you know you can recover from it) then you can catch it. If you don't know of a way of handling the exception at that level, don't catch it; you have no idea what state you are in and whether or not you can continue running.






Re: .NET Base Class Library Exception Message Globalisation Best Practices

CommonGenius.com

I have to agree with Peter. I am currently working on a project that follows the "keep running at all costs" philosophy, and it is an absolute nightmare. The application is constantly being put into an inconsistent state because exceptions are being caught in high-level handlers that have no idea what to do with them. This leads to additional exceptions being thrown later on as the bad state manifests itself in other ways. These exceptions are logged, of course, but since there are usually several exceptions being thrown for each problem, its difficult to trace back to the root cause. Debugging the application becomes almost impossible. And since the state becomes so corrupted, the user ends up having to restart the application anyway, defeating the whole point of the exception handling in the first place.

It is theoretically possible to build a library which is capable of maintain consistent state regardless of exceptions being thrown. However, implementing such a library requires something akin to an undo stack, and maintaining such a stack quickly become a memory and performance drain. For the vast majority of applications, the more "pragmatic" approach is to handle errors when you can, and gracefully exit when you can't, allowing the user to restart the application.






Re: .NET Base Class Library Exception Message Globalisation Best Practices

nobugz

Hi Peter,
Do me a favor and check out Scoble's interview of Joel Spolsky. Joel has a very interesting insight in the problem with the quote feature of forums. A more appropriate quote from my post might be:
The latter is *much* harder to implement







Re: .NET Base Class Library Exception Message Globalisation Best Practices

CommonGenius.com

I think we all agree that the second is harder to implement. Peter used your quote about pragmatism because it is that statement that he takes issue with. Part of pragmatism includes feasibility of implementation, and if one method if significantly harder to implement than another, can you really say that it is more pragmatic




Re: .NET Base Class Library Exception Message Globalisation Best Practices

Anonymous

In one of the links (http://codebetter.com/blogs/karlseguin/archive/2006/04/05/142355.aspx) Peter provided I read:

"For example, if a user's registration fails because the email is already in use, throwing an exception might not be appropriate"

Has anybody got any opinions/advice on how to report errors/failures to the user in a scenario such as this Also remember that along with reporting the errors I also need to localise the message associated with the error.

I worked on a Java project before where an exception would be thrown for a scenario like this. The exception message text was a key that was used to get the localised full message that was displayed to the users. I need to know is there a better way to provide this type of functionality in the .Net framework





Re: .NET Base Class Library Exception Message Globalisation Best Practices

Peter Ritchie

Anonymous wrote:

In one of the links (http://codebetter.com/blogs/karlseguin/archive/2006/04/05/142355.aspx) Peter provided I read:

"For example, if a user's registration fails because the email is already in use, throwing an exception might not be appropriate"

Has anybody got any opinions/advice on how to report errors/failures to the user in a scenario such as this Also remember that along with reporting the errors I also need to localise the message associated with the error.

I think we're spanning two topics here: 1) catching exceptions and 2) throwing exceptions. Depending on where you are in your code, informing the user of problems isn't possible. For example, if you're deep in library code when you realize that the email is already in use, displaying a message to the user is problematic: you don't have a parent window to ensure the message box is displayed properly, or the code has no idea if it's being used by something with a user interface. The best course is to throw an exception so the error can go directly to a level that can handle it (which could be several levels deep in the call stack).

If, on the other hand, you call a method that could throw this exception, catch it at a point where you *can* inform the user (e.g. you do know you're running with a user interface and you do have a Form object to ensure MessageBox.Show is displayed correctly.

Anonymous wrote:

I worked on a Java project before where an exception would be thrown for a scenario like this. The exception message text was a key that was used to get the localised full message that was displayed to the users. I need to know is there a better way to provide this type of functionality in the .Net framework

It largely depends on the exception. So exceptions, unfortunately, are overloaded to the point where you *have* to parse the message as it's the only differentiating data (bad). SqlException is similar but a little better; you can check a consistent Number property to get more information on the exception. Ideally there should be one exception per condition; but with SQL Server that's a bit onerous. The problem then lies in knowing how to handle the exceptions as most framework methods mearely document that a particular exception might be thrown, but not the differentiating details (like SqlException.Number).

If you have to parse the Message property, that's what you have to do to "handle" the exception; that's just not the best way to design an exception class. For example:

catch(EmailException exception)
{
if(exception.Message == "Email already in use")
{
MessageBox.Show("You've entered an email address that is already in use...");
}
//TODO: else, handle other messages
else
{
throw;
}
}

Anyone reading along will probably note, if EmailException was a Framework class it won't always return "Email already in use" for this exception; that will be translated depending on the .NET installation. But, sometimes that's all you're given.






Re: .NET Base Class Library Exception Message Globalisation Best Practices

Peter Ritchie

CommonGenius.com wrote:
I think we all agree that the second is harder to implement. Peter used your quote about pragmatism because it is that statement that he takes issue with. Part of pragmatism includes feasibility of implementation, and if one method if significantly harder to implement than another, can you really say that it is more pragmatic
Agreed. I took "pragmatic" to mean you're suggesting this is a better solution despite being harder to implement. "Pragmatic" meaning "practical". By providing no equivalent evaluation on the first point, one can only assume you intended to imply it was impractical or not capable of being realized.

If that wasn't the case then I'm agreeing with you Hans...






Re: .NET Base Class Library Exception Message Globalisation Best Practices

Anonymous

Thanks for all the help so far everyone!!

I¡¯m not planning on just having one type of exception, I plan on catching and logging the exceptions as normal, but in some cases I¡¯ll want to let the exception bubble it¡¯s way back to the users so that they are aware of the fact an error/exception has occurred, if they have the ability to do something about it i.g. use a different email address to register.

I was planning on something like:

try

{

// ¡­

}

catch(MyException e)

{

ErrorPanel.Messages += Translator.GetMessage(e.Message);

}

Would it be better to use the Data collection of the Exception class to add the key I want to use to do the translation

E.g.

try

{

// ¡­

}

catch(MyException e)

{

ErrorPanel.Messages += Translator.GetMessage(e.Data[¡°i18nMsgKey¡±]);

}





Re: .NET Base Class Library Exception Message Globalisation Best Practices

Peter Ritchie

Anonymous wrote:

Would it be better to use the Data collection of the Exception class to add the key I want to use to do the translation

E.g.

try

{

// ¡­

}

catch(MyException e)

{

ErrorPanel.Messages += Translator.GetMessage(e.Data[¡°i18nMsgKey¡±]);

}

The context of where the exception gets caught depends on what you display to the user. I would tend not to directly rely on the exception for the message. The Data member, I assume, is populated upon construction of the exception. You don't know at the point the exception is thrown what (or whether) message will need to be displayed to the user.