Global - Application_OnStart question

S

Shiv Kumar

I see that the Application_OnStart event is fired only once for a certain application.

I'm interested in creating a "global" object (an object that will be available to all requests for the application). I thought I could use this event to create an instance of my object.

I find that the event does get fired and an instance is created. However, when I reference this object from a page it is null. What gives?

What is the recommended way to declare, create etc. my class such that an single instance is created (application wide) and that all my pages have access to this object.

I don't mind if I have to make this object thread-safe and a singleton either. I'd just like to know the recommended way and if this is at all possible.
 
K

Kevin Spencer

If you want a class to be global to the Application, you have to put it into
a global memory area for the Application, such as the Application Cache. The
Application Cache is a Collection, and the elements in it are global to the
entire Application. Be aware, however, that the Application Cache has
expiration, and you need to handle the expiration of the elements in it.

--
HTH,
Kevin Spencer
..Net Developer
Microsoft MVP
Big things are made up
of lots of little things.

I see that the Application_OnStart event is fired only once for a certain
application.

I'm interested in creating a "global" object (an object that will be
available to all requests for the application). I thought I could use this
event to create an instance of my object.

I find that the event does get fired and an instance is created. However,
when I reference this object from a page it is null. What gives?

What is the recommended way to declare, create etc. my class such that an
single instance is created (application wide) and that all my pages have
access to this object.

I don't mind if I have to make this object thread-safe and a singleton
either. I'd just like to know the recommended way and if this is at all
possible.
 
M

Martin

I find that the event does get fired and an instance is created.
However, when I reference this object from a page it is null.

Are you sure you are referencing the same thing you created earlier? If you create an object and put it in an application variable like

Application["MyObject] = new MyObject();

you should be able to access it from any page like so:

Application.Lock();
MyObject obj = (MyObject)Application["MyObject];
Application.UnLock();


Application_Start is a perfect spot to create your object. An explanation for your problem could be that the code in Application_Start fails somewhere before the creation of your object. You may want to try to put your creation statement first and try again.

Martin.

I see that the Application_OnStart event is fired only once for a certain application.

I'm interested in creating a "global" object (an object that will be available to all requests for the application). I thought I could use this event to create an instance of my object.

I find that the event does get fired and an instance is created. However, when I reference this object from a page it is null. What gives?

What is the recommended way to declare, create etc. my class such that an single instance is created (application wide) and that all my pages have access to this object.

I don't mind if I have to make this object thread-safe and a singleton either. I'd just like to know the recommended way and if this is at all possible.
 
S

Scott Allen

The singleton pattern is a well accepted and reusable way to create
your object. If it is inside the same assembly (project) as all your
pages they will be able to reference the object without even lookin in
Application state.
 
S

Shiv Kumar

Are you sure you are referencing the same thing you created earlier?

Yes. The Global object has a property of my class type. So from within a Page I refer to it as Global.xxxx (Of course ApplicationInstance has been type casted here).

Even a regular int variable is incremented in Application_OnStart but when I read it from a page it is zero (not incremented). But I can see the execution go into Application_OnStart, create my object (or increment the count variable).

The issue it seems is that the Global object is instantiated twice by the ASP.NET framework. The first time the Application_OnStart event is fired as well. But the next time it is not. It looks like the previous reference of Global is over written new one has not had at shot at the Application_OnStart event.
Application["MyObject] = new MyObject();

I haven't tried this...
 
S

Shiv Kumar

Thanks Scott for the confirmation. However, what's the best place to
instantiate an instance? Granted, as a singleton my question then becomes
moot. Just seeing that the Application_OnStart event gets fired only once..
 
M

Martin

Shiv,
Yes. The Global object has a property of my class type. So from
within a Page I refer to it as Global.xxxx (Of course ApplicationInstance
has been type casted here).

Show us the property get code.
The issue it seems is that the Global object is instantiated twice by the
ASP.NET framework. The first time the Application_OnStart event is fired
as well. But the next time it is not. It looks like the previous reference of
Global is over written new one has not had at shot at the
Application_OnStart event.

I must say I had a similar experience the other day when I was trying to figure out what was happening. I created an XmlDocument in the application object which I had updated and written to file by application and session events. At one point I seemed to have two different documents, triggered by two different browser sessions. I could tell by the toggling contents of the disk file. I then made the XmlDocument member static just to be sure I would have only one but it should of course not matter if application were a singleton. Which it should be... Which you and I found out it is not at all times...

It may again lead back to the problem I had. Make absolutely sure you have no failing code in any of the application events, preferably clear them all and start to buildup again piece by piece, doing tests in between additions.

Martin.
 
S

Shiv Kumar

Martin,

The property accessor is normal :) It returns the private variable that was assigned in the Application_OnStart event. Are you suggesting I use the Application's hashtable to store my instance?

protected void Application_Start(Object sender, EventArgs e)

{

count++

}

public int Count { get { return count; } }


My application is a bare bones app. I'm trying to wrap my head around some of the ASP.NET nuances so besides an int variable I have a simple object. That's it.

Even in the case above, Count will be Zero. I can see it being incremented the first time, but when I look at from within a page its zero.
 
M

Martin

The property accessor is normal :) It returns the private variable that was
assigned in the Application_OnStart event. Are you suggesting I use the
Application's hashtable to store my instance?

protected void Application_Start(Object sender, EventArgs e)

{

count++

}

public int Count { get { return count; } }


I was suggesting you didn't know how to use properties in C#. I take it you declared the member itself as

private int count;

somewhere up in your application class. I would also say it should work. Why not post the entire "bare bones" application class? This is getting interesting.
 
S

Shiv Kumar

Here is the code from by Global.asax.cs file

public class Global : System.Web.HttpApplication

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.IContainer components = null;

private int count = 0;

public Global()

{

InitializeComponent();

}

public int Count { get { return count; } }


protected void Application_Start(Object sender, EventArgs e)

{

count++;

}



Here is the code from the Page

private void Page_Load(object sender, System.EventArgs e)

{

Label1.Text = ((WebApplication1.Global)Context.ApplicationInstance).Count.ToString();

}


I can see that the count variable is getting incremented once. But the label on the page displays a zero.
 
M

Martin

Shiv,

You're right, I am experiencing the same thing here. If I increment count in
Session_Start as well and I debug, it appears that while in
Application_Start count is incremented but when it enters Session_Start the
value is already reset. If you initialize it to 100 you will see it flips
back to 100.

If you make count static, it works as expected (!). It seems we have more
than one application. Here's more proof.

Declare this in Global:

private static Global theApp = null;

Put this in Application_Start:

theApp = this;

Put this in Session_Start:

Boolean b = theApp.Equals(this);

and debug. You'll see that our one-and-only would-be-singleton application
object suffers from serious multiple personality disorder.


It looks like the application is recreated after Application_Start. Not nice
at all, looks like a serious bug to me. Now I'm sure some Microsoft employee
will respond claiming this is "behavior by design". I am very much
interested in the design philosophy at this point.

Martin.
 
S

Scott Allen

As you predicted, this behavior is by design. :)

There is a pool of HttpApplication objects that ASP.NET uses to
service requests. The runtime pairs each incoming request with an
HttpApplication object, and the object services the request until the
response is complete, then the object returns to the pool.

The runtime invokes the Init method on ALL HttpApplication objects,
while Applicaiton_OnStart only fires once and on the first
HttpApplication object in the pool.

For more info, see Working with HttpApplication Instances:
http://msdn.microsoft.com/library/d.../cpconworkingwithhttpapplicationinstances.asp
 
S

Shiv Kumar

Scott I think both Martin and I are fully aware of the explanation you gave
:)

But that's not the point. The Application_Start event does fire only once
(as expected) however, this is the sequence of things that happen.

1. Global's constructor is called.
2. The Global descendant's constructor is called. (this is the class that
ASP.NET creates on-the-fly

[System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]

public class Global_asax : WebApplication1.Global {


private static bool __initialized = false;


public Global_asax() {

if ((ASP.Global_asax.__initialized == false)) {

ASP.Global_asax.__initialized = true;

}

}

}



3. ___initialized is false this time and so it is set to true.

4. Application_Start is fired.

5. Global's constructor is called again! (Not sure why, but all fields are
initialized since it's a new instance. And this is where there problem is
and the reason the problem exists)

6. Global's descendant's constructor is called again (this is expected since
it is really the descendant being re-created that causes the ancestor's
constructor to be called)

7. This time

__initialized is true

8. But this time Application_Start is not fired as a result we have a fully
reinitialized global instance as a result the property Count is zero.
 
S

Shiv Kumar

and debug. You'll see that our one-and-only would-be-singleton application
object suffers from serious multiple personality disorder.

Exactly right. Two instances of Global's descendant are being created not
just one.
 
M

Martin

There is a pool of HttpApplication objects that ASP.NET uses to
service requests. The runtime pairs each incoming request with an
HttpApplication object, and the object services the request until the
response is complete, then the object returns to the pool.

The runtime invokes the Init method on ALL HttpApplication objects,
while Applicaiton_OnStart only fires once and on the first
HttpApplication object in the pool.

Which makes it effectively a static constructor in .NET programming
semantics. This is not reflected by the C# code and therefor utterly wrong.
One cannot expect a programmer to learn a language and then accept the fact
that one particular runtime environment (ASP.NET) haves its own way with the
semantics. I consider this very serious.
For more info, see Working with HttpApplication Instances:
http://msdn.microsoft.com/library/d.../cpconworkingwithhttpapplicationinstances.asp

I understand we should override Init and Dispose to get the very behavior we
were up until now expecting from Application_Start and Application_End
(thank you very much for this brilliant nomenclature). And yet, an
application is not really an application. We must either go back to the ASP
1.0 days and work with application variables exclusively (which still seem
to be shared across different application objects) or declare everything in
application static to fix what the ASP.NET team screwed up. It sucks! And it
is likely causing a lot of headaches in the ASP.NET community.

Martin.
 
S

Scott Allen

Shiv:

Based on your description, it appears you are still thinking of Global
as a singleton, but it is not.
5. Global's constructor is called again! (Not sure why, but all fields are
initialized since it's a new instance. And this is where there problem is
and the reason the problem exists)

If you have a breakpoint set on the constructor for Global, you will
see it "called again" because there is more than one instance of
Global used by the ASP.NET runtime. There may be 5 running at a time,
maybe 100 - the point is there will be more than 1.

You are only initializing your "count" variable in one of the many
HttpApplication objects.


HTH,


--s
 
S

Scott Allen

Martin:

I agree it is confusing because we tend to think of something with
"application" in the name as being a singleton for our application.
But see inline comments.


Which makes it effectively a static constructor in .NET programming
semantics. This is not reflected by the C# code and therefor utterly wrong.
One cannot expect a programmer to learn a language and then accept the fact
that one particular runtime environment (ASP.NET) haves its own way with the
semantics. I consider this very serious.

It is definably not a static constructor - it is not even a static
method. The docs are quite clear that you should only use
Application_OnStart to modify variables that are shared (static)
amongst all the instances.
http://msdn.microsoft.com/library/d.../cpconworkingwithhttpapplicationinstances.asp

I understand we should override Init and Dispose to get the very behavior we
were up until now expecting from Application_Start and Application_End
(thank you very much for this brilliant nomenclature). And yet, an
application is not really an application. We must either go back to the ASP
1.0 days and work with application variables exclusively (which still seem
to be shared across different application objects) or declare everything in
application static to fix what the ASP.NET team screwed up. It sucks! And it
is likely causing a lot of headaches in the ASP.NET community.

If you want to keep a simple variable like count around, one of the
many places you could keep the variable is in application state, i.e.

Application["count"] = 0;

That is exactly what application state is designed for by being a
global, thread safe, and efficient container. I don't view this as
some sort of "fall back to the old days" as it is still a viable
solution.

Alternatively you can build a singleton class. Here is a great
reference:
http://www.yoda.arachsys.com/csharp/singleton.html

I can understand where the class name is confusing, but if you want
singleton behavior there is just no avoiding the static keyword.

--s
 
M

Martin

Scott,
I agree it is confusing because we tend to think of something with
"application" in the name as being a singleton for our application.

The main reason for my fiece response is that I feel tricked by these
constructs. Some things one just takes for granted based on experience and
the assumption that there is "one application object in one's application"
is one of those things. It may all be well documented, you just assume that
1 + 1 equals 2 regardless the environment.

Once you are aware of them a couple of inconsistencies are not that hard to
live with. It would have meant a lot if Visual Studio would have generated
comments that warn us about these issues, like it does for generated
skeleton code in MFC applications. An update of the ASP.NET Web Application
wizard would be nice.

Martin.
 
S

Shiv Kumar

Scott,

Yes, I see how my previous post might lead you to believe that I expect
Global to be a singleton. But I don't.

Let me ask the question this way. What would one use the Application_Start
event for? I'm not really trying to do something like increment a count of a
variable :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top