Export (0) Print
Expand All
3 out of 13 rated this helpful - Rate this topic

Instrumentation for .NET Compact Framework Applications

.NET Compact Framework 1.0
 

Mark Arteaga
Microsoft Compact Framework MVP
Neoteric Software Development Company
http://www.neotericsdc.com

March 2005

Applies to:
   .NET Compact Framework
   Microsoft Windows CE
   Microsoft Windows CE .NET
   Windows Mobile 2003

Download the .NET Compact Framework Sample: Instrumentation.exe.


Summary: This article addresses designing/architecting your mobile application to provide you with the ability to monitor the level of your application's performance and to diagnose errors when technical problems occur in the field. Except for mobile devices, this article builds on the "Logging Application Block" and "Exception Management Application Block" from the Microsoft Patterns and Practices site. The architecture includes a mobile or embedded device and a desktop client to be able to view the instrumented data. One of the key goals of this article is to provide an "Application Block" for instrumentation of a mobile application and help minimize problem resolution time when something does go wrong. (12 printed pages)

Contents

Introduction
Overview
CFIL Design Overview
Developing Using CFIL
CFIL Extensibility
Included Libraries
TestBed Application
Desktop Client
Conclusions
Resources

Introduction

There are many stages to a mobile project (and any project in general), from getting a project sponsor, gathering business requirements, development, deployment, support, and so on. One stage that often is overlooked is the support stage, including designing your application for instrumentation while your mobile application is out in the field.

What happens when you have released your application to the field, there is a problem, and the response you get from the user is "It doesn't work!" or "I click the button and nothing happens." This is a support person's and developer's nightmare because no one knows where to start to attempt to find a solution. You could have the user retrace their steps but that usually doesn't help. I hope that, by using the techniques discussed in this article and the library provided, the pain of supporting mobile applications in the field will be alleviated.

Overview

The "Compact Framework Instrumentation Library" (CFIL) is a combination of the following from Microsoft Patterns & Practices:

  • Logging Application Block (LAB)
  • Microsoft Instrumentation Framework (MIF)
  • Exception Management Application Block (EMAB)

Because we are on a constrained device we will have cut back on a lot of the functionality from the above three items and combine them into one. Also, there are a few differences from the original Application Blocks.

  • Desktop client to view the data on the device.
  • Since the .Net Compact Framework is a subset of the full Framework, we will use OpenNETCF.org Smart Device Framework (SDF) to supplement missing functionality from the Compact Framework.
  • Limitations in the Compact Framework (for example StackTrace) cause us to hardcode some values, such as the method name. With Version 2 of the Compact Framework this will no longer be necessary.

CFIL Design Overview

The CFIL is a combination of the Logging Application Block, Microsoft Instrumentation Framework, and the Exception Management Application Block; two of which are on the MSDN Patterns & Practices site. (See Resources for more information.) The CFIL framework was designed to be a central repository for all errors and any other diagnostic information that needs to be logged. Although it is a combination of the above three, it is not as feature-rich as we are on a constrained device. CFIL was designed to be lighter than the above three for performance reasons.

Figure 1. CFIL classes

Instrumentation Manager

The InstrumentationManager class is the main entry point into the CFIL. It is implemented using the Singleton Pattern, so only one instance is created per application. Figure 2 shows the publicly available methods within the InstrumentationManager. Primarily the library provides a Publish() method for error logging and StartPerfCounter() and StopPerfCounter() for performance tracking (more on this below). Internally, the library also uses the OpenNETCF.Diagnostics.TraceEx and listens for any events from the trace log and publishes the trace information.

Figure 2. InstrumentationManager class diagram

Internal Classes

Internally the InstrumentationManager uses OpenNETCF.Diagnostics.EventLog to log all instrumented data and the default XMLEventLogWriter provided was used. Although a custom EventLogWriter could be written, I will leave that as an exercise for you, the reader.

Since the Compact Framework version 1 does not provide any tracing capabilities, OpenNETCF.org has implemented an OpenNETCF.Diagnostics.TraceEx to supplement the missing functionality. Internally the library implements a custom trace listener (CFILTraceListener), which basically just raises an event to the InstrumentationManager. The InstrumentationManager then takes the trace data and publishes it to the log.

IPublisher

The InstrumentationManager exposes a property called Publisher that allows the user of the library to implement a custom CFIL publisher. By default, CFIL loads the DefaultPublisher to handle all the log writing. More on this later.

Features

CFIL provides a few features that are worth mentioning. First, the DefaultPublisher uses a separate background thread to publish any data to the log. This helps improve some performance issues with XMLEventLogWriter, since it uses XMLDocument, which inherently performs poorly on large documents. (I did write XMLEventLogWriter originally and am looking at writing a better implementation.) Second, CFIL exposes a property called SnapshotOnError that will provide a screen capture of the screen when an error is published. This can be useful in some circumstances that arise out in the field and gives some sort of starting point as to what happened. Since a screen capture is an approximately 250 KB bitmap, the log file would become extremely large with just four errors that needed a screen capture. The DefaultPublisher overcomes this by using GZip compression (provided by SharpZipLib), which compresses the image approximately 80 to 90 percent.

Developing Using CFIL

Developing using CFIL is pretty straightforward. A few simple steps are required to use the library.

  1. Call CFIL.InstrumentationManager.Initialize() method in the library.
  2. Use OpenNETCF.Diagnostics.TraceEx.WriteLine() to publish tracing information.
  3. Use CFIL.InstrumentationManager.Instance.Publish() to publish exceptions.
  4. Use StartPerfCounter and StopPerfCounter to measure performance of certain items.
  5. Call CFIL.InstrumentationManager.Instance.Dispose() to close the library properly.

CFIL.InstrumentationManager.Initialize()

Since the InstrumentationManager implements the Singleton design pattern, the object will get created only when the CFIL.InstrumentationManager.Instance property is used. Internally this will create the Singleton object and in the constructor of the InstrumentationManager all relative objects get created, for example the CFILTraceListeners and EventLog.

To overcome this, an Initialize() static method was added to initialize the Singleton object. The call to Initialize() is not a mandatory requirement but is recommended. It was included to give the user the ability to initialize the library at the beginning of the application instead of when the Instance property was used.

public Form1()
{
   InitializeComponent();
   Neoteric.CFIL.InstrumentationManager.Initialize();
}

One item of note: if TraceEx.WriteLine() is used without calling Initialize() then these trace items will not be logged, since the CFILTraceListener is not added to the TraceEx.Listeners, which is set up in the constructor of InstrumentationManager.

TraceEx.WriteLine()

Since .NET Compact Framework version 1 does not provide any tracing capabilities, OpenNETCF.org has implemented this functionality in the Smart Device Framework (SDF). The TraceEx class gives the developer the ability to add tracing information throughout the application. TraceEx can be useful for tracking user application usage and could also be useful in tracking errors and/or bugs. The sample below traces the following, which will be written to the log:

  1. btnTestTrace_Click
  2. Trace1()
  3. Trace2()
  4. Trace3() throws an exception that will be caught and published by btnTestTrace_Click().
    private void btnTestTrace_Click(object sender, System.EventArgs e)
    {
       try
       {
          TraceEx.Write(this.GetType().ToString() +  ".btnTestTrace_Click()");
          this.Trace1();
          this.Trace2();
          this.Trace3();
       }
       catch(Exception ex)
       {
          this.im.Publish(ex,null);            
       }
    }
    
    private void Trace1()
    {
       TraceEx.WriteLine(this.GetType().ToString() +  ".Trace1()");
    }
    private void Trace2()
    {
       TraceEx.Write(this.GetType().ToString() +  ".Trace2()");
    }
    private void Trace3()
    {
    throw new Exception("Exception on " + this.GetType().ToString() + ".Trace3()");
    }
    
    

CFIL.InstrumentationManager.Publish()

The Publish() method would primarily be used when an exception is caught. The parameters taken are the Exception and a NameValueCollection for any additional information. (Note: The DefaultPublisher does not use the additional information.)

try
{
   …
}
catch(Exception ex)
{
   this.im.Publish(ex,null);            
}

CFIL.InstrumentationManager.StartPerfCounter/StopPerfCounter

These methods where added to give the user the ability to monitor performance of certain methods—for example, a Web service call. If your application is generally performing poorly, you may want to review Developing Well Performing .NET Compact Framework Applications, specifically, tracking performance counters, since Start/StopPerfCounter is not intended to be a replacement. Here is a sample on using these methods:

try
{
   PerfItem pi = this.im.StartPerfCounter(this.txtKey.Text,this.txtDesc.Text);
   //loop 5000 times and do some stuff
   for(int x =0; x<5000; x++)
   {
      int t = x;
      int add = t+(x+1);
      int y = add;
   }
   this.im.StopPerfCounter(pi);
}
catch(Exception ex)
{
   this.im.Publish(ex,null);            
}

StartPerfCounter will return a PerfItem object. This or the supplied "key" can be used to stop the performance counter on the item. StopPerfCounter() will automatically publish the data to the log.

CFIL Extensibility

CFIL was designed to be used out of the box, or it can be extended by the user. CFIL provides an interface called IPublisher that a class can implement and that can be used as a custom publisher. All that is need is to set the Publisher property to the custom publisher and you are ready to go. An example of a custom publisher is to use SQLCE and have that data replicated back to a SQL Server backend.

Included Libraries

There are three libraries that helped make CFIL possible and a lot faster to develop. First, there are the libraries from the OpenNETCF Smart Device Framework (SDF) and the OpenNETCF.org Desktop Communication Library. Parts of the SDF that were used were included in the CFIL build for two reasons. One, the ability to save binary data (screen capture image) was needed for the EventLog, so a slight modification was made to XMLEventLogWriter.cs to use Base64 Encoding. Two, since this change is not in version 1.2 of the SDF, the decision was made to compile it within CFIL instead of distributing a separate assembly. This change will be in version 1.3 of the SDF; at that time a new CFIL may be released to work with version 1.3 of the SDF.

The Desktop Communication Library is used for the Desktop Client to get access to a connected device. No modifications have been done there.

The second library used was #ziplib to add compression to the screen captures. By using #ziplib, the 250 KB bitmap size is reduced to approximately 9 KB. The code required to zip (or compress) the bitmap was compiled into CFIL with a small change to StreamManipulator.cs to get the library compiled against the .NET Compact Framework.

To download the original source for the libraries above, please see the Resources section below.

TestBed Application

The TestBed sample application is a test application to test all functionality within CFIL. This is not an exhaustive application, but is merely used to show the functionality for CFIL and an example of how it can be used in your application.

Figure 3. TestBed application

Desktop Client

The Desktop is used to read the logged data created by the CFIL DefaultPublisher.

Note   If a custom publisher is created, the desktop client will not work with the custom publisher data. If you extend CFIL by creating a new publisher, you will have to create your own log viewer.

Figure 4. Desktop client screenshot

Desktop Client Points of Interest

A few items that may be of interest to developers from the desktop client are the ability to connect remotely to a device using RAPI and a remote device file browser. The desktop client has the ability to open files on the local desktop or on a device connected via ActiveSync. A sample log file (CFIL.log) is included in the source code.

Figure 5. Opening a log file

To connect to a remote device, the OpenNETCF.Org Desktop Communication Library (which uses RAPI) is used to copy the log file from the device to be viewed on the local computer. The desktop client will also change the icon and the status bar to visually notify the user if there is a device connected or not.

Figure 6. Device not connected

Figure 7. Device connected

Another point of interest is a remote file browser. Since RAPI doesn't provide a GUI interface for selecting files on a remote device (but does provide methods for finding files), a "Device File Browser" was implemented to copy log files from a device to the local desktop to be viewed with the desktop client.

Figure 8. Device File Browser

Conclusions

This article examines the use of an Instrumentation Library for the .NET Compact Framework. It describes the internal architecture and the sources used to develop the library. Developers should be able to use CFIL out of the box within their applications and extend the library by building custom publishers if needed. The desktop client is used to view the logged data and also shows what can be done with RAPI on a remote device. I hope this library will give developers the ability to more easily monitor the health of their applications and help you debug problems when you get those difficult user responses.

Resources

Here are some resources that helped make this library possible:

 

About the Author

Mark Arteaga is Software Development Consultant/President of Neoteric Software Development Company (http://www.neotericsdc.com), architecting and designing solutions using both Microsoft .NET Framework and Compact Framework. Mark has been in the computer industry for the past six years designing, architecting, and developing software for various projects. During the past three years his focus has been primarily on mobile projects utilizing Windows CE, PocketPC, SmartPhone, and .NET Compact Framework. He is also actively involved in the OpenNETCF.org project, which specifically targets improving the Microsoft .NET Compact Framework through open source projects.

Neoteric Software Development Company can implement end-to-end solutions, help organizations conquer challenges they are facing, and also help organizations go through the various phases of a project life cycle, from creating a business case, design/architecture, development, deployment, and creating a support system.

If you have any comments or questions you can contact Mark at marteaga@neotericsdc.com. You can also check out his personal blog for more .NET Compact Framework tips and libraries at http://blog.markarteaga.com.

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.