would
be
a
case where the Page creates some object and then passes it to the
thread.
Does your thread change Session, or does it perhaps only change
something
which is referred to by Session? For example, does your thread do:
Session["index"] = value;
or
MyClass mc = (MyClass) Session["index"];
mc.Property = value;
? The latter makes some sense, while the former does not. How does your
thread know that Session doesn't expire after the page has
completed
and
while it's still using it?
If you're doing the latter, why not pass (MyClass)
Session["index"]
to
your
thread instead of having the thread reference Session?
Be very careful with threads in ASP.NET. Often, the kind of thing we
would
do in a Windows application doesn't make sense in light of the ASP.NET
page
model.
Thanks for your help, John. I have done some work on this over the past
week. The session IS available in the child thread, even after the
spawning
page has been emitted. When calling the thread I also passed a reference
to
the session using the following technique:
Thread MyThread = MyThreading.CreateThread
(new MyThreading.MethodDelegate(MyAsyncMethod),
HttpContext.Current.Session);
MyThread.Start();
public class MyThreading
{
/// <summary>
/// Pass the name of the method that the thread is to run
/// </summary>
public delegate void MethodDelegate(object method);
/// <summary>
/// This class serves to wrap a method with arguments as a method
/// without arguments, suitable for running in a new thread.
/// </summary>
private class ThreadWork
{
public object TheMethodArgs;
public MethodDelegate TheMethodDelegate;
public void Work()
{
TheMethodDelegate(TheMethodArgs);
}
}
/// <summary>
/// Creates a thread based on a method delegate and the method args.
/// The method should be defined as MyMethod(object args).
/// </summary>
/// <param name="methodDelegate">A new MyThreading.MethodDelegate
for
the
method to run</param>
/// <param name="methodArgs">An object holding all the arguments to be
passed to the method to run</param>
/// <returns>a new System.Threading.Thread which can then be
started</returns>
public static System.Threading.Thread CreateThread(MethodDelegate
methodDelegate, Object methodArgs)
{
ThreadWork NewThreadWork = new ThreadWork();
NewThreadWork.TheMethodArgs = methodArgs;
NewThreadWork.TheMethodDelegate = methodDelegate;
System.Threading.Thread NewThread = new System.Threading.Thread
(new System.Threading.ThreadStart(NewThreadWork.Work));
return NewThread;
}
}
Ok, so you've now determined that this "works", and I'm sure that you're
right. It will work right up until the time that it stops working.
If you haven't seen any examples of this from Microsoft, then you should
assume that it isn't meant to "work forever" until or unless you hear
otherwise from Microsoft.
Consider: if you pass a reference to Session into your thread, then Session
will certainly not be garbage-collected until your thread removes its
reference to it. But are you sure that Session will not be Disposed?
Or
that
ASP.NET (which created Session and could be said to own it) will not do
anything nasty to it? Keep in mind that ASP.NET is unaware of the existance
of your thread and has no reason to take your thread into account.
You want to be passing things to your thread which are owned by you, and
which you can control. For instance, if you currently have five
variables
in
Session, say Session["a"] through Session["e"], then I suggest that you
create a class with the five values in it:
public class ForSession
{
public object a;
public int b;
public int c;
public object d;
public string e;
public ForSession(object A, int B, int C, object D, string e) {...}
}
And put an instance of that class into Session:
Session["ForSession"] = new ForSession(...);
Then, pass that to your thread:
Thread MyThread = MyThreading.CreateThread(new
MyThreading.MethodDelegate(MyAsyncMethod), (ForSession)
Session["ForSession"]);
You would own this object entirely, and nothing that ASP.NET could
decide
Interesting. But the purpose of my "ForSession" object is to maintain
status/progress information across postbacks. If the session dies then the
issue of the object dying with it is moot.
Not exactly. My point is that your thread could potentially still be
executing when the session dies - ASP.NET won't exactly keep the session
around for the benefit of a thread it knows nothing about. Worst things
could even happen: ASP.NET could keep the session alive as far as aspx pages
are concerned, yet the references you're working with in your thread could
wind up being Disposed or worse.
In general, keep in mind that ASP.NET doesn't know anything at all about
your thread. Your thread is using something which came from ASP.NET without
its permission. ASP.NET is free to take your toy away or do anything else to
it that it likes, all without your knowledge. I'd be especially concerned
about things it might do to implement session persistence in SQL Server or
the state server.
Another issue that comes to mind
is, how does the object inside the thread get synched with the same object
as referenced thru the session from another thread (postback)? What if I was
using a database session server, as opposed to in-proc? How could that
work?
As I said above, you've already got that same problem. You think that your
thread is processing "the same session object as the page which started it",
but the page is gone now! ASP.NET will guarantee that the next page
requested by the "same user" within a reasonable amount of time will see the
contents of Session as they were at the end of the request which started
your thread. But there is no reason to believe that your thread, which is
not a page, will be able to do anything sensible with Session.
I'm starting to feel that the only reliable way to do this is to persist my
ForSession object to a database between reads/updates.
Whatever you do, make sure you do something "on your own". Do not depend on
accidents of ASP.NET implementation, especially not where multiple threads
are involved. In my opinion, you shouldn't even be using another thread
spawned from an ASP.NET page for the simple reason that ASP.NET shouldn't
have to take your thread into account. As a simple example, ASP.NET will
restart the current AppDomain if web.config changes. It won't wait for your
thread to finish before doing so, neither will it warn your thread ahead of
time!
ASP.NET doesn't really "do" threading. It does "do" multiple simultaneous
HTTP requests. You can expect the latter to work, but you should have no
expectation that the former will continue to work past the next patch you
apply to your server.