Presents your XML AND WEB SERVICES E-NEWSLETTER for December 1, 2003 <-------------------------------------------> IMPLEMENT AN HTTPAPPLICATIONSTATE OBJECT A typical requirement in many Web applications is to implement some kind of a page-hit counter, or application-hit counter. When implementing this in a regular .aspx page, the solution is pretty simple. The solution for Web services is also a fairly straightforward process, with a couple of additional considerations. Examining the code required to implement two different Web service counters may be useful when collecting performance and usage metrics for your application. HTTPAPPLICATIONSTATE HttpApplicationState is a class built into the .NET Framework that's available to all request handlers invoked within an application. By default, all Web services have access to the HttpApplicationState object because they inherit it from System.Web.Services.WebService. There are a few considerations you must take before using the Application state variables in an application. 1. Memory usage: It's important not to store large volumes of data in the Application object because the long lifespan of the objects stored in it will degrade your server's memory performance. 2. Synchronization: The built-in Collection objects used by the Application object aren't thread-safe. Therefore, it's possible to have multiple threads access or manipulate data in the Application object at the same time. 3. Life-cycle durations: Remember that Application object values only last as long as the application itself, which can be brought up or down at any time for maintenance, upgrades, etc. 4. Multi-server environments: Application state isn't shared among multiple servers. If your application is run in a server farm environment, the Application state object only reflects usage for the particular server the application is being run on. There's also the adage that using the Application or Session objects in any context is a bad practice. There are many arguments on both sides of this debate. Before implementing the Application object, you should consider all risk factors. APPLICATION COUNTER EXAMPLES Let's take a look at some code that tracks two types of Application counters. One of the counters acts as a global counter, tracking the number of times any Web service has been called. The second tracker is specific to a single Web service, which will track the number of times a specific Web service has been called. LISTING 1.0 shows the Web service code, containing the code for both counters, plus some simple test methods that will increment the counters. Listing 1.0 Imports System.Web.Services _ Public Class WSCounter Inherits System.Web.Services.WebService Private Sub IncrementGlobalCounter() Application.Lock() Application("GlobalCounter") += 1 Application.UnLock() End Sub Private Sub IncrementSpecificCounter(ByVal CounterName As String) Application.Lock() Application(CounterName) += 1 Application.UnLock() End Sub Public Sub Method1() ' Increment the global Web Service counter Me.IncrementGlobalCounter() 'execute Web method code........ End Sub Public Sub Method2() 'Increment the global Web service counter Me.IncrementGlobalCounter() 'Increment the Web Service specific counter Me.IncrementSpecificCounter("WSCounter") 'execute Web method code...... End Sub Public Function GetGlobalCounter() As String Return Application("GlobalCounter") End Function Public Function GetSpecificCounter(ByVal CounterName) _ As String Return Application(CounterName) End Function End Class The IncrementGlobalCounter() method increments an Application variable called "GlobalCounter" each time it's called. The IncrementSpecificCounter() method takes in a CounterName parameter and increments a counter in the Application object of this name. You'll notice that these methods have Application.Lock() and Application.UnLock() methods wrapping the access to the Application object. Wrapping access to the data in the Application object with these calls ensures that other threads will not modify the data concurrently. Method1() increments only the global counter, while Method2() increments both the global counter as well as a counter named "WSCounter", which is the name of the Web service itself. USAGE When implemented in every method, the two counters will allow you to track the number of times a particular Web service has been called, as well as how many times all of your Web services have been called. You could also increase the granularity of the counter methods to track particular methods. That would create an abundance of different Application objects and should only be used if you're collecting performance and usage statistics. You may also want to track the start date of the application on the assumption that the application can be brought up and down at will. This will give you a more accurate track of the counters between given date and time ranges. For performance reasons, you may want to implement a simple way of turning on and off Application objects in your Web services by adding a simple property to your Web.Config file, which would be read from the methods that increment the counters. If the property is false, you would bypass all code executing Application object access. This would require an additional If/Then wrapper around your Application object code, but it provides for greater flexibility. BE CAREFUL An Application object variable is basically a global variable, which can cause unexpected results when used incorrectly. By keeping the usage of the Application object to simple non-critical data usage, and by implementing some of the performance measures mentioned, you can take advantage of the functionality without sacrificing system performance or data integrity. Kevin Koch is a senior software engineer with extensive experience in both Microsoft's .NET platform and J2EE technologies. He is a cofounder and president of Task Solutions Inc. ----------------------------------------