RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Resuscitate Your .NET Programs with the Application Recovery and Restart API  : Page 2

Please your users by making your applications recover intelligently and restart smoothly after failures with this .NET-savvy integration wrapper for the Application Recovery and Restart API.

Registering for Application Recovery
Developers have always taken steps to minimize terminations and hangs without using Application Recovery and Restart, such as handling exceptions properly and avoiding deadlock, but it's difficult to anticipate every source of failure. When your application terminates or hangs, the host operating system takes over—enter the Windows Error Reporting (WER) service.

WER detects application failures and takes steps to make it easier for Microsoft and third parties to see and troubleshoot application failure trends. If your application fails, WER displays the dialog box in Figure 2 while it collects information about the failure.

Figure 2. Application Failure. When a registered application fails, Windows Error Reporting (WER) collects information.
Run the sample application and then type "a" to abort the main thread and invoke WER.

Aborting the main thread isn't the only way to invoke WER; after registering an application, you'll also see this dialog box whenever the application fails to handle an exception, doesn't respond appropriately to a Windows close or shutdown message, or stops responding to Windows messages. The sample DevX.ServerApplication aborts the main thread to invoke WER because it's hosted in a Windows console application, so it will always respond to Windows messages and close properly.

When WER has finished collecting information about the failure, it will give your application an opportunity to recover data and state before unloading the process from memory. Listing 1 demonstrates how to use the ApplicationRecoveryRestart.RegisterApplicationRecoveryCallback method to instruct WER to call your ApplicationRecoveryRestart.ApplicationRecoveryCallbackDelegate during the recovery process.

There is a lot going on in Listing 1; here's a more detailed explanation of the required steps.

The first step in registering for application recovery is to properly declare the ApplicationRecoveryCallbackDelegate in the ApplicationRecoveryRestart class. The Windows SDK C language declaration for the callback is in winbase.h:

      (PVOID pvParameter);
When you expose this callback to your .NET application via a P/Invoke class it's best practice to convert the PVOID parameter to a more specific type, because the conversion adds a layer of type safety to an otherwise ambiguous parameter that moves back and forth between your .NET application and kernel32.dll.

The following code defines a custom RecoveryInformation class that you can use for the parameter type in the application recovery callback delegate.

   // Custom recovery information class
   public class RecoveryInformation
       // Insert your custom recovery information here
       public string Message;
   // The recovery callback delegate as defined 
   // by Application Recovery and Restart
   public static class ApplicationRecoveryRestart
       public delegate Int32 ApplicationRecoveryCallbackDelegate(
           RecoveryInformation parameter);
       // ...
Author's Note: Plan to replace the RecoveryInformation class in the sample application with one that more closely satisfies your application's recovery requirements.

The second step in registering for application recovery is to call the ApplicationRecoveryRestart.RegisterApplicationRecoveryCallback method, which accepts four parameters:

   public static extern Int32 RegisterApplicationRecoveryCallback(
       ApplicationRecoveryCallbackDelegate recoveryCallback,
       RecoveryInformation callbackParameter,
       UInt32 pingInterval,
       UInt32 flags);
All this information gets sent to the callback when your application fails. The first two parameters are an instance of the callback delegate and an instance of the recovery information class. The pingInterval parameter determines how often (in milliseconds) WER sends a heartbeat to your application during recovery to make sure it's responding. The recommended value is 5,000 milliseconds (5 seconds), while the maximum value is 5 x 60 x 1,000 milliseconds (5 minutes).

The fourth parameter is reserved for future use; pass in zero.

Author's Note: As of this writing, the MSDN documentation for RegisterApplicationRecoveryCallback and GetApplicationRecoveryCallback incorrectly specifies the pingInterval parameter units as 100-nanosecond intervals.

The following methods demonstrate how to retrieve your application recovery settings with GetApplicationRecoveryCallback and reset your application recovery settings with UnregisterApplicationRecoveryCallback.

   // GetApplicationRecoveryCallback 
   // as defined by Application Recovery and Restart
   public static extern Int32 GetApplicationRecoveryCallback(
       IntPtr process,
       out ApplicationRecoveryCallbackDelegate recoveryCallback,
       out RecoveryInformation parameter,
       out UInt32 pingInterval,
       out UInt32 flags);
   // Retrieving application recovery settings
       confirmRecoveryCallback = null;
   RecoveryInformation confirmParameter;
   UInt32 confirmPingInterval;
   UInt32 confirmFlags;
       out confirmRecoveryCallback,
       out confirmParameter,
       out confirmPingInterval,
       out confirmFlags);
   // Resetting application recovery settings
The next step is to implement your recovery callback.

Implementing Application Recovery
The most important task for your application recovery callback is to attempt to prevent data loss or corruption; only you know the exact mechanisms required to do so for your application. However, some of the tasks to consider implementing include:

  • Compare in-memory data to saved data to determine if there is a potential for loss or corruption. Save the recovered data if possible.
  • Log information about the failure and the application state.
  • Give the user an opportunity to take action or make any necessary decisions.
WER needs to know that you're making progress while attempting to recover after an application failure. You must call ApplicationRecoveryInProgress within the ping interval you passed into RegisterApplicationRecoveryCallback. For example, if you passed in the recommended value of 5,000 for the ping interval, then your recovery callback must call ApplicationRecoveryInProgress every 5 seconds at a minimum. If you don't, then WER will assume your application wasn't able to recover and unload the process from memory.

   public static extern Int32 ApplicationRecoveryInProgress(
       out Boolean canceled);
Figure 3. Recovery Dialog: Calling ApplicationRecoveryInProgress allows the user to see that recovery is under way and cancel the operation if necessary.
WER displays the dialog box in Figure 3 when you first call ApplicationRecoveryInProgress.

That dialog gives users the option of cancelling the recovery. If a user clicks Cancel while your application is trying to recover, the next call to ApplicationRecoveryInProgress will return true in the canceled parameter. You may choose to cancel recovery efforts if this is the case.

When you're done recovering application data, call ApplicationRecoveryFinished to notify WER that your process is ready to be unloaded from memory.

   public static extern void ApplicationRecoveryFinished(
       Boolean success);
Here's how the DevX.ServerApplication sample program simulates recovery tasks:

   public static Int32 ApplicationRecoveryCallback(
      RecoveryInformation parameter)
           // Make sure the parameter arrived
           Console.WriteLine("-- Invoking recovery callback --");
           Console.WriteLine("The message passed in through " + 
              "the recovery information parameter is: {0}", 
           // Simulate the process of recovering data
           bool canceled = false;
           for (int i = 0; i < 5; i++)
                  ApplicationRecoveryInProgress(out canceled);
               Console.WriteLine("Application is recovering...");
               if (canceled)
                       "User canceled application recovery.");
           // Notify Windows that recovery is complete
           Console.WriteLine("Application finished recovering.");
       catch (Exception ex)
       return 0;
Figure 1 shows the output for the simulated application recovery.

Properly recovering your application data puts your application in a position to restart safely, and Windows can help.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date