2005-10-23
| Table of Contents: |
| Rate This Article: | Add This Article To: |
( Page 3 of 3 )
What About Regular Statics?
As with any static data, if you code your classes correctly, you can swing it so your statics throughout your program get created when the application starts, even those outside of HttpApplication.
In this case, such static data is initialized each time the ASP.NET runtime starts up your application.
I've used this technique myself, but be forewarned: this is not the official Microsoft-approved way of creating static data, so as usual, use at your own risk.
One way to accomplish such static initialization is to throw a line in your class, like the one below, shown in bold.
In this code, the Inst member is initialized when the application starts up (at least technically speaking; I say more about this shortly). Then you don't need a Setup function, and you don't need to do anything inside your Global.asax file. You can simply access the data in the same way as before, through the GetInst() static function.
Public Class Globs1
Protected Shared Inst As Globs1 = New Globs1
Public Shared Function GetInst() As Globs1
Return Inst
End Function
Public Function SomeValue() As Int32
Return 10
End Function
Protected Sub New()
Logger.WriteLine("Startup")
End Sub
End Class
If you test out this code by putting a breakpoint on the Logger line, you'll find ASP.NET is actually quite smart and the object might not get created until it's actually used. Either way, it works.
This approach might look slightly familiar, if you looked over the Logger class I provided earlier. That class uses this same technique. The class includes a static initializer that creates the single instance of the Logger class. But in this case, I don't provide any public member functions, other than a single shared function, WriteLine. Since this function is shared, I saw no reason to provide a function for accessing the singleton instance, either. Instead, the function accesses the singleton instance itself.
With this approach, however, note that I offer a very big caution. Because you don't have control over exactly when your instance is created, you also can't be sure that all the intrinsic objects were created. (By intrinsic objects, I mean things like the HttpContext instance, for example.) In general, I've found that such objects are available by the time my static object is created by this method; however, Microsoft warns against such things, and we had better listen. Thus, for important production or mission-critical code (unlike my Logger class), I always make sure I include a Setup function that I call from the Application_Start event. But for smaller applications where I'm not as worried, I use this approach, and I have never had a problem.
What if you want to allow code in your program to be allowed to modify the global data? Yuck.First, let me say this: Consider redesigning your code. Global data shouldn't be a free-for-all. But if you insist (since there are, of course, some valid times), you should lock the data before you write to it. ASP.NET runs in a multithreaded universe, and if two threads try to modify the data simultaneously, the whole multithreaded universe will explode. (Or at the very least, the data will become corrupt and unstable.) To learn about locking, look in the online help for the
HttpApplicationState.Lockmethod. Oh and remember, locking like this can cause your application to slow down a great deal, if you have to do a lot of locking. You've been warned.
A Singleton-on-Demand Class
The previous example creates the instance at some time before you need it, but it's not totally clear when the runtime system gets around to making the instance. So how about a one-better class that initializes the data the first time you need it? Here's one an example:
Public Class Singleton2
Protected Shared Inst As Singleton2 = Nothing
Public Shared Function GetInst() As Singleton2
If Inst Is Nothing Then
Inst = New Singleton2
End If
Return Inst
End Function
Protected Sub New()
pHeight = 20
pWidth = 30
End Sub
Dim pHeight As Int32
Dim pWidth As Int32
Public ReadOnly Property Height() As Int32
Get
Return pHeight
End Get
End Property
Public ReadOnly Property Width() As Int32
Get
Return pWidth
End Get
End Property
End Class
This class is almost exactly the same as the previous Singleton1 class, with two notable exceptions, shown in bold. First, I added some lines to the GetInst function that look for the existence of the single instance, and if the instance doesn't exist, create it. Next, to cover my beehive, I initialized the singleton instance, Inst, to Nothing, just to be extra-guar-own-teed that the test if Inst is Nothing will succeed the first time. Oh yes, and I also get rid of the Setup function and removed its call from the Global.asax file.
Now if you've been around the block a few times, you might recognize this code as the correct way to implement a singleton pattern, without any undue influence from the aggressive ASP.NET runtime — except for the locking mechanism I put in place just to be sure nothing gets trampled on in the even two threads end up calling GetInst at precisely the same time. Also, this code doesn't suffer from the same problem as the previous example, in which you can't be sure the intrinsic variables all exist. The reason is I make sure that I only call GetInst from within my forms and from within code called by my forms, at which point the intrinsic variables all definitely exist.
What does all this mean? Global singleton instances work in ASP.NET just as you would expect and hope they do. However, remember that your application might unload and get reloaded at any time; don't use this code to create an instance of something that expects to be up and running all the time. And make sure you write code that is okay shutting down and restarting from time to time. (But shouldn't all programs meet that requirement, anyway?)
And finally, remember once again that your application doesn't load separate copies for every single user. That means each user doesn't get a set of global static variables. The variables are shared among all users as long as the application is running.
But Wait! What About...
If you've done some exploring of ASP.NET, and especially of the earlier pre-.NET days of ASP, you might wonder why you don't just store your global data in the Application list, which is well-documented. Well, you can. Inside the code for a form you can use the intrinsic Application variable like so:
Application("appname") = "CoolApp"
Or, outside form code, you can access the Application variable through the HttpContext class, like this:
HttpContext.Current.Application("appname") _
= "CoolApp"
However, Microsoft recommends against this practice. The only real reason this feature exists is for backwards compatibility with old ASP programs. But why not use it? One big reason is speed. If you've got a high-traffic Web site, and you're doing a lot of lookups to the Application object, you need to seriously concern yourself with every little thing that takes up time, because they all add up. And accessing your static data directly is much faster than trying to access the data through a hash array, such as the Application object.
Plus, since the Application object is for backwards compatibility, we have no guarantee Microsoft will keep it in every future version of ASP.NET. It's best to keep up with the times.
Another Tangent: Manually Restarting Your ApplicationWhen you're developing your application and dealing with static data, you probably need to restart the application several times, so you can actually get your changes in and test things out. If you need to restart your application, there are a few things you can do.
In theory, you should only have to rebuild your application for ASP.NET to restart it. However, I've found doing so to be unreliable, especially with ASP.NET 2.0, where your individual aspx files get compiled into separate assemblies; sometimes the system doesn't automatically restart the application. I've had times where I've modified a class that's initialized in the
Application_Startevent, and when I rebuilt and run the application, I've received a whole bunch of null pointer exception errors, because for whatever reason theApplication_Starteven didn't actually occur yet. Thus, I've had to force the reload of my application.One quick way to force the application to reload is to "touch" the
Global.asaxfile. (You do have a Touch command on your computer, right? That's a program that does nothing more than update the date and time of a given file to the current date and time. It's a very useful tool for developers, and you can do a Web search to find one. Or heck, just write one yourself if you can't find one.)Here's another method. Okay, maybe I'm a bit of a brute at times when dealing with this amazingly intricate yet delicate system based around an expensive, high-tech central processing unit, but this is a quick and dirty way to kill my application. (And no, I'm not going to say throw the computer out the window, even though sometimes I feel that way.) I just open up the Task Manager, find the
aspnet_wp.exename in the Processes tree, and clickEnd Process. IIS immediately restartsaspnet_wp.exewith a clean start. Yeah, yeah, that's dirty, as it doesn't let your application do any proper shutdown and cleanup. But on my own development box, it works just fine, and it's quick. (But use this method at your own risk. Don't sue me if you lose all your sales data doing this.)
No Static Here
As with all things Microsoft, you have to be very aware of the implications of seemingly small tasks, such as creating static data. With ASP.NET, you especially have to be aware of everything going on behind the scenes, considering that you will probably have multiple people accessing your application, and ASP.NET is a rather sophisticated (read: complex) system.
As I tell my students and coworkers, study up on the documentation and learn what's going on under the hood. Static initialization is no exception. Mind your Ps and Qs, and you'll get it working well, and without bugs.
![]() |
|


