views:

597

answers:

5

I have a web app that currently uses the current HttpContext to store a LINQ Data Context. The context is persisted for the current request, on a per user basis, per Rick Strahl's blog:

string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x")  
Thread.CurrentContext.ContextID.ToString();

if (!HttpContext.Current.Items.Contains(ocKey))
{
    // Get new Data Context and store it in the HTTP Context
}

However, I have some scripts that execute from the global.asax file, that don't have an HttpContext. The HttpContext.Current is NULL, because the server is the one making the "request".

Is there an equivalent object that I can use to store the Data Context? So I don't have to worry about re-creating it, and attaching/detaching objects? I only want to persist the context for the lifetime of my processes.

UPDATED:

I am currently trying to use a static variable in my DAL helper class. on the first call to one of the methods in the class the DataContext is instantiated, and stored in the static variable. At the end of my process, I call another method that calls Dispose on the DataContext, and sets the static variable to NULL.

+4  A: 

Can you not just use a static variable specifically for those scripts? That will have the same life-time as the AppDomain. You should probably think carefully about any concurrency concerns, but it sounds like the simplest way to keep a value around.

(I've just checked, and although one instance of HttpApplication can be used to service multiple requests, each one only serves one request at a time - which suggests that multiple instances are created for concurrent request processing. I haven't validated this, but it does sound like it wouldn't be safe to keep it in an instance variable.)

EDIT: Josh's answer suggests that you want this to be per-thread. That sounds slightly odd to me, as unless you've got a lot of these events occurring, you're quite likely to only ever see them execute on different threads, making the whole sharing business pointless. If you really do want that sort of thing, I'd suggest just using an instance variable in the HttpApplication-derived class - for exactly the reason described in the paragraph above :)

Jon Skeet
Jon, this is right. Each application serves only one request at time.
XOR
Do you mean "each deployed web application" or "each instance of HttpApplication"? Does a single web application create multiple instances? Serializing all requests to a deployed application sounds like performance death to me - surely that can't be the way of things.
Jon Skeet
I only have 1 instance of this web application running on 1 box. I just want to have these processes run in the background and do some work. When they run, I want the Data Context to be persisted during the operation, so I don't have to worry about recreating it and attaching entities.
SkippyFire
So I think the static variable in my DAL class should do the trick. I'll let you know how it goes.
SkippyFire
Good point, doesn't the time fire on different threads each time? At least there is no guanretee it will fire on a specific timer.
JoshBerke
Each served request has its own set of core objects - HttpApplication, HttpRequest, HttpContext and so on. So I ment one instance of HttpApplication serves one request at time. Problem is: if you don't have request (as with timer) you don't have "your" appliaction instance.
XOR
+1  A: 

Why not use the current HttpContext? The scripts in your global.asax file are all the result of a request coming into the server, so there should be a context associated with that request which you can grab.

I don't understand the need for generating the key based on the hashcode or the thread. There is going to be a separate instance of HttpContext for each request that comes in, and that instance is going to be specific to the thread that is processing the request. Because of that, the key is pretty much worthless when it's based on the instance of HttpContext and the thread.

Also, how do you dispose of the DataContext when you are done? It implements IDisposable for a reason, so I would recommend against a shared instance like this.


UPDATE

In the comments, it indicates that there is a timer that is running that is executing the scripts. Instead of the timer, I would recommend setting up a Scheduled Task which will call a webservice or predetermined page on the site which will perform the task. Then you will always have an HttpContext to work with.

casperOne
I had the same thought about his HttpContext but since he is spawning threads, there wouldn't be a context.
JoshBerke
@Josh: There is no indication that he is spawning threads to run these scripts. The functions are in global.aspx. If it is the standard set of events for that module, then they come in response to requests to the server.
casperOne
Check his comment. He says he has some timers that run periodicaly created during App_Start
JoshBerke
The HttpContext.Current value is always null whenever the requests start from my timers. Otherwise, yeah, I'd just use that!
SkippyFire
@Josh: He should have put that in his question.
casperOne
Originally I said that the scripts "don't have an HttpContext", but I guess people missed that.
SkippyFire
A: 

HttpContext.Current is a static method and should be available from anywhere as long as the code is executing within the context of a request.

In your case your not executing within the context of a request, You could look at using Application.Cache but I would caution against holding a DataContext open. I am not very famillar with linq to entities, so I could be wrong, but generally caching data base related items such as connections is bad.

I would also recommend that you consider moving the logic out of your global.asax and to a windows service. This would let you have more control over these tasks, for example you can shut them down seperatley of the web site.

Edit

As JS points out you could use a static variable. You could also define an instance variable marked with ThreadLocal attribute. This will give each thread its own copy of the variable, and can eliminate contention. Since you want each thread to have its own copy anyways.

JoshBerke
A: 

Is there a reason why these need to be handled the same way as the other DataContexts? It seems to me that if the context is only needed inside the event handling routine, you shouldn't need to keep it around. Especially if it is in Application_Start (as per your comment), I wouldn't bother caching it anywhere -- just use it locally and pass it to the other methods as needed.

tvanfosson
A: 

Set the DataContext as the state parameter when creating the timer. Based on the info you posted on the comments, it seems to me that your DataContext is more related to the timers than anything else.

Also avoid using the same DataContext for different timers, because you would end up with mixed modifications from the different timers. Also make sure your same timer logic isn't run twice, since it would cause the same i.e. too short period with no control.

eglasius