Category Archives: Error Handling

Direct integration of ILMerge with VB.net Projects

0
Filed under .NET, Error Handling, MSBuild, Troubleshooting

I’ve been working on a few utility type applications lately (more on them later, once they’re firmed up), but one thing I’ve found incredibly useful for certain projects is ILMerge.

If you’re not familiar with it, ILMerge is a utility that essentially can combine two or more .net assemblies into a single assembly, and reducing an application’s footprint is something I’m particularly passionate about!

In the past, I’ve always created postbuild steps that included executing ILMerge as just a command line post build process, but doing it this way has always been problematic. To start, debugging in the IDE tends to be compromised at best, and not possible at worst. Plus it just never felt clean.

In researching the problem, I ran across three blog posts that have provided more than enough info to get me past the Post Build process and actually integrate ILMerge directly into the build process itself, and one very intriguing alternative.

First, Scott Hanselman wrote about his experiences using ILMerge to merge a VB.net assembly into an otherwise C# project back in 2007. A great article and a fantastic first step.

Then, I came across Daniel Fortunov’s  article about integrating ILMerge into the VS build process. His example is also very good and a little cleaner, I’d say than Scott’s approach, but both articles are definitely worth checking out if you find yourself needing this kind of thing.

Lastly, Jeffrey Richter wrote a terrifically short but incredibly eye-popping article about a technique to load .net assemblies dynamically from binary resources baked into a single assembly at compile time. Very simple and clean. A great technique to have in your toolbox if the need ever arises.

For my part, I’ve used the ILMerge technique to merge Mono.Cecil.dll (a C# library from the mono project for directly altering .net assemblies) into a VB.net utility that can repackage portions of an assembly’s PDB file directly into the assembly’s EXE or DLL file, to supply line numbers during the rendering of an exception’s stack trace without actually have to provide a PDB (and all the additional metadata about your assembly) to your client. A fantastic debugging technique and one that I’ve been working with (off and on) for several years now. I’ll write about it in more detail later.

A Reasonable Approach to Exceptions

1
Filed under Error Handling, VB Feng Shui

A comment thread on LinkedIn today ended up pointing me to an article by Eric Lippert about Vexing Exceptions.

The article is a little old (around 2008), but I found it to be one of the best-reasoned articles on exception handling I’ve seen.

In it, he basically categorizes exceptions into 4 types:

  • Fatal – You can’t predict and can’t do anything about it
  • Boneheaded – Results from a bug in your code
  • Vexing – Results from a bad design (like Integer.Parse)
  • Exogenous – Results from outside factors, but can be handled by your code.

Fatal and boneheaded exceptions you can’t do anything about (at least not initially). The best defense against them is a good logging framework that allows for multiple logging levels, like off, normal, and debug  for instance.

Vexing Exceptions are those that result from a poor API design. The example Eric gives is the Integer.Parse function. It will throw an exception when the parsed text doesn’t result in an integer, but that’s the whole point of parsing the text in the first place! With vexing exceptions, I usually try to find an alternate implementation that simply doesn’t generate the exception. When that’s not possible, you wrap the block in a Try and just eat the exception. It’s the only other choice you have.

Exogenous exceptions are probably the most typical exceptions you’ll handle in normal code. These are exceptions that you can generally deal with when they occur, but you can’t write code such that they won’t occur, because they are caused by factors outside your code. The typical example is a File Not Found error. Your code can usually easily recover from this type of error, but there’s simply no way to code around it such that you can guarantee it won’t happen.

Which actually leads me to an additional conclusion Eric touched on.

Pre-coding Exceptions (or Why you shouldn’t)

Often, I’ll see (and have certainly written more than once) code such as:

if not FileExists(MyFile) then

   Msgbox “The File Doesn’t exist”

else

   OpenFile MyFile

   Read/Write/Whatever

   Close MyFile

End If

This is an example of an exogenous error that I’m trying to “Code around”, using the FileExist function to detect whether the file is there before trying to open it.

Unfortunately, because there’s no way to predict when the file in question might be deleted, you can still get a file not found error at the OpenFile line, because other code may have deleted the file between the execution of the FileExists test and the OpenFile command itself.

Because of this, it’s often just a waste of time and code to put the FileExists test in, since to be truly covered, you also have to trap for the FileNotFound exception.

And since most exogenous exceptions fall into this pattern, I generally don’t try to code around them anymore. Rather, I just put the appropriate Try Catch blocks in place and deal with those exceptions that way.

Try

   OpenFile MyFile

   Read/Write/Whatever

   Close MyFile

Catch Ex as FileNotFoundException

   Msgbox “The File wasn’t found”

Catch Ex2 as Exception

   ‘Handle other exceptions as applicable
End Try

To do otherwise means you’re likely to miss exceptions occasionally, or you’ll be doing more coding than necessary (and repeating yourself, an even worse situation).

Typical Application Types

What Eric’s post didn’t touch on was exception handling strategies for different application types.

Most applications will fall into a few distinct types. Granted, you’ll always have drivers, embedded systems, and others that have even more specific error handling needs, but I generally see these types most often.

Command line applications

Your typical command line app is single purpose, with a host of command line switches to control its behavior. For these apps, I generally set up a single TRY CATCH in the sub Main to log or display to the console any unhandled exceptions, and then use a few scattered try blocks throughout the processing code to handle any vexing or exogenous exceptions. Everything else, just let fall back to the main Try block, since the run has basically been fatally terminated anyway.

Event driven UI applications

For these, I usually setup a thread exception handler and a process wide exception handler, just to prevent the application from failing completely with no logging of any sort.

Then, I always setup try blocks in the sub Main, and in every non-trivial event handler, at a minimum. “Non-trivial” here means any event handler containing code or calls to code that could possibly result in an exception.

And finally, I use a small scattering of Try blocks to deal with code where I expect there “could” be an exception, even though there normally won’t be, but that I can adequately handle in any case.

For this scenario, I’ve found that an AOP (aspect oriented programming) approach, using something like PostSharp or Spring.net, is a quick, easy and very maintainable way to get these try blocks in place.

Function Libraries

Since function libraries typically don’t (and shouldn’t) display any UI components, I generally let any unexpected exceptions bubble out of the library code back to the caller naturally.

On some occasions, it’s necessary to expose new exceptions from the library. In those cases, I usually create an MyLibrary.Exceptions namespace, containing all the custom exceptions that might be thrown from my library, and then throw them when appropriate.

Logging

No discussion on exception handling would be complete without mentioning logging. Any non-trivial app really should have a logging framework in place. Two of my (free) favorites are Log4Net, and NLog.

They’re both very similar, very capable and very easy to use. Log4net is the “old guy on the block” having been around for a number of years now. NLog is the newcomer, but very capable none-the-less.

Both make configurable logging so trivially easy, it’s almost criminal not to use them.

And, realistically speaking, exception handling is a much more powerful concept when coupled with a comprehensive logging strategy.

Finally, logging is a perfect use case for AOP, so definitely investigate some of the AOP frameworks when you start down this path.