Jim Rogers

Lives in Baton Rouge, LA, with two dogs, one cat, and one lovely wife. I'm a lead developer for GCR Incorporated.

Katrin and Jim

Month List

WPF Worker Thread Exceptions

by Jim Jun 23, 2008 8:37 PM

What if you want to do global exception handling with worker threads? My scenario involves data methods that may be called synchronously, on the UI thread, or asynchronously on a worker. I would like to use the same global exception handling for both.

The problem with this scenario is that unhandled exceptions in the worker thread may cause the application to terminate; there's no handler you can use or flag you can set to prevent this.

One way of handling this is explained as a side note in MSDN's Application.DispatcherUnhandledException documentation:

  1. Handle exceptions on the background thread.
  2. Dispatch those exceptions to the main UI thread.
  3. Rethrow them on the main UI thread without handling them to allow DispatcherUnhandledException to be raised.

I guess they thought the code was too obvious to bother providing an example...

That list is mentioned in the MSDN forums, where an example was promised, but not delivered.

try
{
    . . . 
}
catch (Exception ex)
{
    . . . 

    // Are we not on the main UI thread?
    if (!Application.Current.Dispatcher.CheckAccess())
    {
        // Unhandled exceptions on worker threads will halt the application. We want to
        // use our global exception handler(s), so dispatch or "forward" to the UI thread.
        Application.Current.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            new Action<Exception>(WorkerThreadException), ex);
    }
    else
    {
        throw;  // Already on UI thread; just rethrow the exception to global handlers
    }
}

The WorkerThreadException method simply re-throws the exception on the UI thread, where it is handled by any global exception handlers that have been defined:

private static void WorkerThreadException(Exception ex)
{
    throw ex;
}

Tags:

Code

Config Merge

by Jim Jun 21, 2008 3:44 PM

Config merge is something I whipped up in response to a discussion with my colleague Jon about config files. Configuration files are always a pain in team development, and I thought this solution was interesting enough to merit a code project article. We'll see. :-)

From the introduction:

This article describes a solution to the perennial problem of config file management for multiple developers and environments. The centerpiece is a command-line tool which merges the base (default) configuration file with a truncated file (the differences or "diff" file.) This diff file contains only those elements which need to be added or changed.

You can find the article and code on code project.

WPF - Getting Default Control Templates

by Jim Jun 20, 2008 9:12 AM

YourLameButton

When templating WPF controls, it's easiest to start with the default template defined in the framework - especially if you only need to make minor changes.

This isn't terribly hard to google, but it can't be blogged enough :-)

I'll give you a few options - pick your poison.

Quick and dirty output to the console

StringBuilder sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
    System.Windows.Markup.XamlWriter.Save(MyControl.Template, writer);
}
Console.WriteLine(sb.ToString());

The output of that is just a single (long and unreadable) line of xaml; it's nice to have the output on multiple lines with indentation.

Nicely formatted output to the console

System.Text.StringBuilder sb = new System.Text.StringBuilder();

System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
settings.Indent = true; 

using (System.Xml.XmlWriter xmlWriter = System.Xml.XmlWriter.Create(sb, settings))
{
    System.Windows.Markup.XamlWriter.Save(MyControl.Template, xmlWriter);
}

Console.WriteLine(sb.ToString());

Formatted output to a file

System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
settings.Indent = true; 

using (System.Xml.XmlWriter xmlWriter = 
   System.Xml.XmlWriter.Create("C:\\Temp\\Template.xml", settings))
{
    System.Windows.Markup.XamlWriter.Save(MyControl.Template, xmlWriter);
}

The last one is my favorite; it's easy to open the file in Visual Studio and check it out, if you're just looking to see how something was done.

Tags:

Code

Images in SQL

by Jim Jun 16, 2008 9:43 AM

StudbilFirst you gotta get those suckers in there. It's someone else's job to write the admin app, and we aren't at that stage of development yet.

To insert an image file straight into an image or varbinary field:

INSERT Users (UserName, Photo) 
SELECT 'Joe', * FROM OPENROWSET(BULK 'C:\temp\studbil.jpg', SINGLE_BLOB) AS X

Or to update an existing field:

UPDATE Users SET Photo = (
SELECT * FROM OPENROWSET(BULK 'C:\temp\studbil.jpg', SINGLE_BLOB) AS X
)
where ID = 32

Now you might want to check the size of the binary field to see if it matches the file:

SELECT DATALENGTH(Photo) FROM Users

To get the photo out of the database, in C#:

if (row["Photo"] != DBNull.Value)
{
    MemoryStream imgStream = new MemoryStream((byte[])row["Photo"]);

    // According to MSDN, we're supposed to keep the stream open for the lifetime
    // of the image, which we can't do. So copy the original image by constructing
    // a new one.
    user.Photo = new Bitmap(Bitmap.FromStream(imgStream));

    imgStream.Close();
}

Many people forget the "keeping the stream open" issue when loading images, and in most cases it won't bite you. But in the case of my WCF service, I get this error if I close the stream and then try to serialize the image:

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+. 
 at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, 
EncoderParameters encoderParams) 
 at System.Drawing.Image.Save(MemoryStream stream) 
 at System.Drawing.Image.System.Runtime.Serialization.ISerializable.GetObjectData(
SerializationInfo si, StreamingContext context) 
 at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteISerializable(
XmlWriterDelegator xmlWriter, ISerializable obj) 
 at WriteBitmapToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , 
ClassDataContract ) 
. . . 

Tags:

Code

Failing a Build

by Jim Jun 15, 2008 12:28 PM

Batch files are one of those things I work with so infrequently that I have to research some aspect of them every time.

Today's problem: How do I intentionally fail the build in Visual Studio when my utility program fails?

To bubble an error from a command-line utility, return an error code from the Main() method:

static int Main(string[] args)
{
    int retval = 0;     // success code

    try
    {
        ...
    }
    catch (Exception ex)
    {
        // Return an error code so the caller knows there was a problem
        retval = 1;
        ...
    }
    return retval;
}

If the pre- or postbuild event called the utility directly, you're done; the build will fail.

But if a batch file called it, you need to catch the error in the batch file and bubble it back up:

MyUtility.exe %arg1% %arg2%
:: In case of error, bubble up to visual studio
IF ERRORLEVEL 1 EXIT 1

That link will also explain how to catch different error codes, in case you need the batch file to do more intelligent processing.

It's also possible to mess around with how Visual Studio handles error codes.