Click Here to Install Silverlight*
IndiaChange|All Microsoft Sites
MSDN
|Developer Centers|Library|Downloads|How To Buy|Subscribers|My MSDN
 
Implementing Centralized User Notification in .NET
By : Rakesh Rajan
 
Article Posted: October 18, 2004
 
Introduction
 
Applications with user interfaces generally notify the user about information, warnings, errors and other forms of status messages occasionally. They make use of message boxes, error providers and similar types of controls to accomplish this. While using these controls, the text for the status messages and its corresponding resources (icon, buttons etc.) usually gets hard-coded. In small scale projects this might not be a cause for concern. However, in large projects with large teams, ensuring consistency across the project for the message text and the resources used will be a major overhead. Each developer might hardcode the message string as he/she would like, which could differ in tense, form and meaning, from what another developer would have coded, though they would have been used in the same context. Ultimately, the end-user would be baffled with the different kinds of status messages he/she receives from the product, even though the user had invoked the same set of actions in each case. If overlooked, this could develop into a significant issue later on.
 
Another dimension to this problem exists as well. If the device the end-user uses is uncertain, or if a project targets different devices, the mode of notification could wary depending on the device. Notifying the user on status updates with respect to the capabilities of the device he/she is currently using might require considerable amount of code. This requirement could be better tackled if the user notification code is centralized. Instead of having each developer in the team burdened with the responsibility to query the device type and modify the notification procedure, the developer will just have to invoke a user notification method, which would abstract all these implementations. This method would in turn, generate the appropriate notification method with respect to the end-users device.
 
In pre-.Net days, developers had different strategies for countering the first scenario. The most common solution sought was to use a string resource file from which the message text to be used would be extracted. In order to extract the messages, you would require an identifier – a string ID, which would act as a key to obtain the resource. But making note of which ID represents which message was a task that made this solution lose its charm.
 
With .NET, effective solutions for handling these problems can be implemented. This article explores a simple centralized messaging design, which would address the issues illustrated above, and also walks you thru a demo implementation of this design in Windows Forms.
 
Overview
 
The general objectives of a design which will address the issues mentioned would be as follows.
 
1. Developers should be able to trigger notification with code that is short and simple.
2. Developers should not be made to remember message identifiers for retrieving the required message resources.
3. The design should ensure that any modifications to the notification implementation will be quick and effortless.
4. The design should abstract the implementation of handling different end-user devices from the developer.
5. It should be ensured that the modifications to message resources could be done easily, and would not affect existing code.
 
To meet these objectives, our design would use a resource file, a messages enumeration and a user notification method.
 
In .NET, resources are generally stored within RESX files. The RESX file format is basically an XML file where objects and strings are defined inside XML tags. Being an XML file, it can be easily opened and modified using text editors. Both textual and binary information can be stored within RESX files. Our solution would use such a file where we would store the message string, the icons and the button type for each message to be shown.
 
All applications belonging to the genre we talked about would have a pre-defined set of message strings. These message strings would represent the complete list of message types that the application would use. One of the best solutions to let the developers select the message type without having to resort to remembering message ids would be to use an enumeration. Enumerations let you organize a set of related constants. Each of these constants is associated with a unique name. In our solution, we would define an enumeration, with as many fields defined for each message we have identified. When coupled with Visual Studio.NET® Intellisense®, developers would only have to select the required message from a list of all message types available.
 
In our design, the enumeration fields we define would also be used as message keys to retrieve the message resources from the RESX file. All objects in .NET have the ToString method. Making use of this fact, we would store message resources in the RESX file using keys with the same name as that of the enumeration field. It would then only be a matter of string generation to extract the required resources.
 
The implementation of the user notification method would take as input the message enumeration. The method would then identify the type of notification required depending upon the type of application and the device targeted. On this basis, the method would extract resources from the appropriate RESX file passing the message enumeration field name. The resources would be cast back to the appropriate types as required.
 
Demo Implementation
 
Let’s have a look at a simple implementation of this design involving the above mentioned elements in a Windows Forms application.
 
This sample will use MessageBox.Show as the user notification method, and will have all the message box elements viz. the message text, message icon and message buttons stored in the resource file. An overview of the design and a detailed step-by-step description follows.
 
 
Step 1 – Defining the Messages enumeration
 
Create an enumeration with the name Messages. Then define fields in the enumeration for each of the message strings you want to display. For example, for a generic exception thrown while closing a window, you could define a field with the name CloseGenericError.
 

public enum Messages
{
    // define as many message types as required
    CloseGenericError,
}

 
Step 2 – Prepare the resources
 
For each of the message fields in the Messages enumeration, add three entries in the resource file – one for the message string, the second for the MessageBoxButtons enumeration and the third for the MessageBoxIcon enumeration. The name field in the RESX for the message string will have the same name as that of the message enumeration field, whereas the name for the MessageBoxButtons and MessageBoxIcon fields will have ‘Buttons’ and ‘Icon’ suffixed to it. For example, if the enumeration field is named CloseGenericError, the values for the name field in the RESX will be ‘CloseGenericError’, ‘CloseGenericErrorButtons’ and ‘CloseGenericErrorIcon’ for the message string, buttons and icon respectively. Also, the values for the type field will be System.String, System.Windows.Forms.MessageBoxButtons and System.Windows.Forms.MessageBoxIcon respectively.
 
Step 3 – Define the Resource Manager
 
For extracting resources from the RESX file, we will make use of the System.Resources.ResourceManager class. For this purpose, we need to define a resource manager instance in our class, which our user notification method will use. We pass to its constructor the base name for the resources and the current assembly. The base name will be root name of the resources. In our case this takes the value “DotNetDays.UIProcessController”. The current assembly can be obtained by using the Assembly.GetExecutingAssembly method.
 

private static Assembly asm = Assembly.GetExecutingAssembly();

private static System.Resources.ResourceManager resources =
      new System.Resources.ResourceManager(
      "DotNetDays.UIProcessController",
      asm);

 
Step 4 – Implement the notification method
 
Next, we need to implement a user notification method named NotifyUser which will accept a Messages enumeration as an argument. When the NotifyUser method receives control, it would extract the required message resources from the RESX file using the static resource manager member variable we just defined. We use the ResourceManager.GetString and ResourceManager.GetObject methods to extract the resources. Both these methods require a key to be passed, which in our case is obtained by calling the ToString method on the enumeration field passed in the argument.
 
Depending on the caller, it can be found out what type of client and the client device the notification is to target. With respect to that, additional resource managers may be used to handle different types of clients. For example, if the caller is a web application, we obviously should use a user control or a separate page for user notification in place of MessageBox.Show. Such requirements could be easily centralized in this method.
 
In a very simple fashion, it can also be adjudged whether this notification should be logged or not on the basis of the enumeration field name. For example, if the name ends with ‘Error’ or ‘Warning’, then this is a notification which probably should be logged. If yes, then we could simply call a logger method to do the same. The developers will no longer have to worry about the extra task of explicit logging.
 

public static DialogResult ShowMessage(Messages msgMessageType)
{
    if(
         msgMessageType.ToString().EndsWith("Error") ||
         msgMessageType.ToString().EndsWith("Warning") ||
         msgMessageType.ToString().EndsWith("Exception")
      )
{
         // invoke the logger
}

return MessageBox.Show(
     resources.GetString(msgMessageType.ToString()),
     "My MessageBox Title",
     (MessageBoxButtons)resources.GetObject(
     msgMessageType.ToString() + "Buttons"),
     (MessageBoxIcon)resources.GetObject(
     msgMessageType.ToString() + "Icon")
     );
}

 
Step 4 – The Notification
 
When all our previous blocks are in place, it is only a matter of a single call to the NotifyUser method to trigger a user notification. The effort from the developer is thus hugely reduced.
 

try
{
      // code
}
catch(Exception ex)
{
      UIProcessController.ShowMessage(Messages.CloseGenericError);
}

 
The Next Steps
 
With this design all details on how a notification is made is abstracted from the developer. Updates to the notification method will be straight-forward and add-ons to the existing implementation will take almost no time. Moreover, this can be clubbed with implementations for globalizing/localizing your application to have a centralized user notification design that works in different cultures.
 
 
Download the source code
(After downloading change the extension of the file to .zip)
 
 
 

©2009 Microsoft Corporation. All rights reserved. Contact Us |Terms of Use |Trademarks |Privacy Statement
Microsoft