Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Distinguishing between .NET exception types

For the love of all things holy, how do you distinguish between different "exception flavors" within the predefined .NET exception classes?

For example, a piece of code might throw an XmlException under the following conditions:

  • The root element of the document is NULL
  • Invalid chars are in the document
  • The document is too long

All of these are thrown as XmlException objects and all of the internal "tell me more about this exception" fields (such as Exception.HResult, Exception.Data, etc.) are usually empty or null.

That leaves Exception.Message as the only thing that allows you to distinguish among these exception types, and you can't really depend on it because, you guessed it, the Exception.Message string is glocabilized, and can change when the culture changes. At least that's my read on the documentation.

Exception.HResult and Exception.Data are widely ignored across the .NET libraries. They are the red-headed stepchildren of the world's .NET error-handling code. And even assuming they weren't, the HRESULT type is still the worst, downright nastiest error code in the history of error codes. Why we are still looking at HRESULTs in 2010 is beyond me. I mean if you're doing Interop or P/Invoke that's one thing but... HRESULTs have no place in System.Exception. HRESULTs are a wart on the proboscis of System.Exception.

But seriously, it means I have to set up a lot of detailed specific error-handling code in order to figure out the same information that should have been passed as part of the exception data. Exceptions are useless if they force you to work like this. What am I doing wrong?

EDIT. A DAY LATER.

Thanks for all the comments and responses. I'm learning a general lesson here ("error messages suck") even if I haven't quite solved the specific problem. Here's the specific scenario I'm deaing with.

Our application consumes XML files produced by a third party. These XML files sometimes contain illegal characters that really have no business being in an XML file. These illegal chars cause a (validating) XmlReader to blow up with an "illegal char on line X" exception". We have to process these files, however; we can't simply tell the user, "sorry, that file doesn't conform to the official XML spec." Our users don't even really know what XML is.

Microsoft has an official (and quite strange to me) recommendation in this case (the case where an XML document contains illegal characters): to load the file into a stream, iterate to the specific line containing the error (as provided, ironically, in the XmlException object), and to custom-replace the offending char with a legal one. Then try loading the doc into the validating XmlReader again, and seeing if it blows up. Here's the Knowledge Base article describing the technique.

So fine, we're doing that, and it works well enough. The problem is that sometimes these XML files we get are malformed in other ways: they might be empty, they might be missing a closing tag, etc. So if you follow the MS recommendation, you're actually hooking your "replace illegal chars" logic into the catch block where you catch the original exception thrown by the validating reader.

That's fine if the exception is in fact an "illegal char" exception. But if it's a "root element missing" or "missing closing tag" exception, you find that the MS technique to go in and replace the offending char itself blows up, because not only is there not an offending char, there are no chars at all, or there are, but they're invalidly-formed XML, or whatever. At this point you're in a doubly-nested catch-inside-a-catch, your hair's turning gray and falling out, your eyes are crimson red with caffeine fatigue, and you're questioning the sanity, let alone the utility, of using validating readers against real-world XML.

So what I need is a way of telling, in that initial catch(XmlException) block, whether this is a "root element missing" or a "invalid char" exception, so I can take the appropriate action. One thing we can't do is prevent our users to open a document that contains a few invalid chars. We have to process those documents regardless, and I guess it's looking like the only solution is to iterate through every char in the document ahead of time, viewing it as a text stream rather than as XML, find the illegal chars, replace them, then load the thing with the validating XmlReader and if it blows up, we know it's not an illegal char exception, because we stripped illegal chars beforehand.

Before doing that I thought I'd at least ask 1) can we get better information out of the XmlException object and I was hoping somebody would tell me 2) "it's okay to key off the XmlException.Message string. They say it's localized but it's not really. This string will be the same across all versions and cultures of Windows."

But nobody has told me that.

like image 339
Swingline Rage Avatar asked Jun 08 '10 14:06

Swingline Rage


People also ask

What are the different types of exceptions in C#?

There are two types of exceptions: exceptions generated by an executing program and exceptions generated by the common language runtime. System. Exception is the base class for all exceptions in C#.

What are the 3 types of exceptions?

There are three types of exception—the checked exception, the error and the runtime exception.

What is the difference between fault exception and regular dot NET exception?

Exceptions are used to communicate errors locally within the service or the client implementation. Faults, on the other hand, are used to communicate errors across service boundaries, such as from the server to the client or vice versa.


1 Answers

I totally agree with you in principle, but the number of instances where I really care about the exact reason the exception was being thrown (in my code) is pretty small.

Using XmlException as an example, is there really some different behavior you would have in your code if the document was too long vs. if it had invalid characters?

The only example I can think of where I've ever really cared was for SQL type exceptions where some errors can be recovered from (e.g. a lost database connection).

ETA:

If you are worried about the culture when keying off the error message, you could just set the current thread culture to the invariant culture while you are processing the document, then set it back to the original culture when you are done. That should ensure that the message will always be the same.

like image 148
Eric Petroelje Avatar answered Oct 09 '22 12:10

Eric Petroelje