Internal ASP.NET threading model
-
Hi, we're making use of the CallContext class (System.Remoting.Runtime.Messaging.CallContext) to easily share information among objects participating in the same threads. We have a base page class from which we derive our pages, and we initialize this context by handling the Init event in the base page. This seems to work rather brilliantly. Just to be sure: It is reasonable, isn't it, to assume that this would either *always* work or *never* work? In other words, since the callcontext travels along the logical thread, the init event will never be executed on a different thread from other events in ASP.NET?
-
Hi, we're making use of the CallContext class (System.Remoting.Runtime.Messaging.CallContext) to easily share information among objects participating in the same threads. We have a base page class from which we derive our pages, and we initialize this context by handling the Init event in the base page. This seems to work rather brilliantly. Just to be sure: It is reasonable, isn't it, to assume that this would either *always* work or *never* work? In other words, since the callcontext travels along the logical thread, the init event will never be executed on a different thread from other events in ASP.NET?
You know that the aspnet process does sometimes get reset... I've nevered needed to use messaging in ASP.Net, can I ask what information you need in multiple threads that can't be stored in the Application state?
I didn't get any requirements for the signature
-
You know that the aspnet process does sometimes get reset... I've nevered needed to use messaging in ASP.Net, can I ask what information you need in multiple threads that can't be stored in the Application state?
I didn't get any requirements for the signature
Hi Todd, I'm afraid you've misunderstood. The CallContext is not for sharing information between threads, but between objects participating in the same thread. ASP.NET itself uses it to provide access to the "intrinsic" objects Request, Response, Server, Handler, Session and so on. The main reason we can't use asp.net intrinsics such as Session or Application state is that our business layer runs in a non-web context as well. Specifically, we have a windows service that implements a scheduler. This being .net, there should be no problem using the same business layer in the web app and the service, but this of course means the business layer cannot rely on anything asp.net specific. Another reason is that we perform many long-running tasks which cannot be performed in a synchronous "request - do the work - create the response" manner, but must instead use one request to start work, then go into polling until the work is finished, then get the results. So another reason to avoid relying on the web context is that it enables us to provide identical execution contexts in the threads our code creates as well as those created by asp.net, so business logic can be developed without having to know in advance whether it will take part in "background" threads or not. We keep only a small amount of information here, but it is absolutely essential: The identity of the user, and database connection information. (It is a distributed system and a single application instance can connect to any number of database instances, while also any number of application instances can connect to any given database instance. Hence we need to know on a user-by-user basis what database the user is "logged on to", though we do of course use connection pooling.) Not using session or app state of course doesn't automatically imply using the CallContext, but it is extremely convenient because it provides isolation between threads, and also because references put into it are removed when the thread ends, so clean-up is automatic much in the same way as with local variables that simply go out of scope. If anyone has the inside knowledge to answer my actual question rather than try to second-guess what I'm asking (no offense, I appreciate the attempt!) then please let me know. I'm really quite convinced though that it is the same logical thread: asp.net events happen in stages and I can see no reason why one would want to complicate matters by switching threads along the way, when the processing anyway must occur in a linear fashion.
-
Hi Todd, I'm afraid you've misunderstood. The CallContext is not for sharing information between threads, but between objects participating in the same thread. ASP.NET itself uses it to provide access to the "intrinsic" objects Request, Response, Server, Handler, Session and so on. The main reason we can't use asp.net intrinsics such as Session or Application state is that our business layer runs in a non-web context as well. Specifically, we have a windows service that implements a scheduler. This being .net, there should be no problem using the same business layer in the web app and the service, but this of course means the business layer cannot rely on anything asp.net specific. Another reason is that we perform many long-running tasks which cannot be performed in a synchronous "request - do the work - create the response" manner, but must instead use one request to start work, then go into polling until the work is finished, then get the results. So another reason to avoid relying on the web context is that it enables us to provide identical execution contexts in the threads our code creates as well as those created by asp.net, so business logic can be developed without having to know in advance whether it will take part in "background" threads or not. We keep only a small amount of information here, but it is absolutely essential: The identity of the user, and database connection information. (It is a distributed system and a single application instance can connect to any number of database instances, while also any number of application instances can connect to any given database instance. Hence we need to know on a user-by-user basis what database the user is "logged on to", though we do of course use connection pooling.) Not using session or app state of course doesn't automatically imply using the CallContext, but it is extremely convenient because it provides isolation between threads, and also because references put into it are removed when the thread ends, so clean-up is automatic much in the same way as with local variables that simply go out of scope. If anyone has the inside knowledge to answer my actual question rather than try to second-guess what I'm asking (no offense, I appreciate the attempt!) then please let me know. I'm really quite convinced though that it is the same logical thread: asp.net events happen in stages and I can see no reason why one would want to complicate matters by switching threads along the way, when the processing anyway must occur in a linear fashion.
I should be more precise about one thing because reading my post I see that I am inviting one misunderstanding: I say that the CallContext is used to provide access to the intrinsic asp.net objects, and that is true. However, I should be more explicit, because otherwise people will think I'm confusing CallContext and HttpContext. So just to be clear, it is the reference to the current HttpContext which is kept in the CallContext, and the other intrinsics come from that one again. Basically what we're doing is a sort of simplistic mimicking of the way it's done in asp.net, believing that this design isn't too bad. You could say our business logic relies on a thread context that has been initialized by our own code rather than one initialized by asp.net framework code; thus enabling us to do such initialization in both our scheduler service and the web application.
-
Hi Todd, I'm afraid you've misunderstood. The CallContext is not for sharing information between threads, but between objects participating in the same thread. ASP.NET itself uses it to provide access to the "intrinsic" objects Request, Response, Server, Handler, Session and so on. The main reason we can't use asp.net intrinsics such as Session or Application state is that our business layer runs in a non-web context as well. Specifically, we have a windows service that implements a scheduler. This being .net, there should be no problem using the same business layer in the web app and the service, but this of course means the business layer cannot rely on anything asp.net specific. Another reason is that we perform many long-running tasks which cannot be performed in a synchronous "request - do the work - create the response" manner, but must instead use one request to start work, then go into polling until the work is finished, then get the results. So another reason to avoid relying on the web context is that it enables us to provide identical execution contexts in the threads our code creates as well as those created by asp.net, so business logic can be developed without having to know in advance whether it will take part in "background" threads or not. We keep only a small amount of information here, but it is absolutely essential: The identity of the user, and database connection information. (It is a distributed system and a single application instance can connect to any number of database instances, while also any number of application instances can connect to any given database instance. Hence we need to know on a user-by-user basis what database the user is "logged on to", though we do of course use connection pooling.) Not using session or app state of course doesn't automatically imply using the CallContext, but it is extremely convenient because it provides isolation between threads, and also because references put into it are removed when the thread ends, so clean-up is automatic much in the same way as with local variables that simply go out of scope. If anyone has the inside knowledge to answer my actual question rather than try to second-guess what I'm asking (no offense, I appreciate the attempt!) then please let me know. I'm really quite convinced though that it is the same logical thread: asp.net events happen in stages and I can see no reason why one would want to complicate matters by switching threads along the way, when the processing anyway must occur in a linear fashion.
dojohansen wrote:
If anyone has the inside knowledge to answer my actual question rather than try to second-guess what I'm asking (no offense, I appreciate the attempt!) then please let me know.
What are you talking about? I didn't try to second guess anything. I've never used messaging in asp.net and I wanted to learn more about it. That's why I asked you...
I didn't get any requirements for the signature
-
dojohansen wrote:
If anyone has the inside knowledge to answer my actual question rather than try to second-guess what I'm asking (no offense, I appreciate the attempt!) then please let me know.
What are you talking about? I didn't try to second guess anything. I've never used messaging in asp.net and I wanted to learn more about it. That's why I asked you...
I didn't get any requirements for the signature
I just meant that it seemed you tried to think about state management in general, hence suggesting application state, when in fact my question was whether or not the entire asp.net pipeline is processed on the same logical thread or not. I didn't mean to upset you, so sorry if I did. I know from when I try to help people that it is often useful to understand the context though, so I try to explain the motivation behind using it. My testing seems to indicate that Global_BeginRequest and EndRequest fire on a different thread from the page processing, but all events fired on the page appear to always belong to the same thread.
-
I just meant that it seemed you tried to think about state management in general, hence suggesting application state, when in fact my question was whether or not the entire asp.net pipeline is processed on the same logical thread or not. I didn't mean to upset you, so sorry if I did. I know from when I try to help people that it is often useful to understand the context though, so I try to explain the motivation behind using it. My testing seems to indicate that Global_BeginRequest and EndRequest fire on a different thread from the page processing, but all events fired on the page appear to always belong to the same thread.
I'd bet money that all page processing occurs on one thread. I did find this on google. http://dotnet.org.za/armand/archive/2004/04/07/985.aspx[^] So it seems you could store and pass data using the CallContext, however judging that only 4 results come back when you google System.Remoting.Runtime.Messaging.CallContext you might have trouble getting any help with this.
I didn't get any requirements for the signature
-
I'd bet money that all page processing occurs on one thread. I did find this on google. http://dotnet.org.za/armand/archive/2004/04/07/985.aspx[^] So it seems you could store and pass data using the CallContext, however judging that only 4 results come back when you google System.Remoting.Runtime.Messaging.CallContext you might have trouble getting any help with this.
I didn't get any requirements for the signature
We're pretty much doing the same thing. It is perfect for providing "execution context" information like who is the current user, what's the current database, and so on. I'm going off on a tangent here, but I actually believe what we've done can be quite useful for others as well. Our design follows this simple pattern: All instance members are private, as are all constructors. The public interface is static, but public members do nothing but find the right instance and call the corresponding instance member. References to instances are stored in the thread context, hence only one thread can access each instance, so the design is inherently thread-safe. A snippet demonstrates the pattern implemented in C#:
public class Connection
{
const string threadKey = "Connection";// Private constructor
Connection(string cnxStr) { ... }// All instance members are private...
int transactionLevel;
SqlTransaction transaction;
SqlConnection sqlConn;
...// .. including methods
void beginTransaction()
{
...
}// A *private* static property gets the current instance.
Connection current
{
get
{
Connection c = CallContext.GetData(threadKey) as Connection;
if (c == null)
{
// This is the only place in the app we need to know where
// connection information comes from. :)
string cnxStr = ...;
c = new Connection(cnxStr);
}
return c;
}
}// The public interface is all static, giving the illusion that there
// is only one connection, when in fact there is one per thread.
static public void BeginTransaction()
{
// Just call the corresponding instance method on "current".
current.beginTransaction();
}
}We couple this with our own custom-written "Thread class" (Thread is sealed so our type is not really a thread, but it has the same interface as a thread so where our code was creating threads we just switched the type to our own) which copies the execution context of the thread that creates it, and we have a wonderfully simple to use solution with a minimum of code redundancy. (The "where do connection info come from" logic was all over the place before, and we had problems knowing when we should clone connections and when we should not, because the method using a connection would sometimes be called as part of a transaction and sometimes without one, sometimes in a thread pr
-
We're pretty much doing the same thing. It is perfect for providing "execution context" information like who is the current user, what's the current database, and so on. I'm going off on a tangent here, but I actually believe what we've done can be quite useful for others as well. Our design follows this simple pattern: All instance members are private, as are all constructors. The public interface is static, but public members do nothing but find the right instance and call the corresponding instance member. References to instances are stored in the thread context, hence only one thread can access each instance, so the design is inherently thread-safe. A snippet demonstrates the pattern implemented in C#:
public class Connection
{
const string threadKey = "Connection";// Private constructor
Connection(string cnxStr) { ... }// All instance members are private...
int transactionLevel;
SqlTransaction transaction;
SqlConnection sqlConn;
...// .. including methods
void beginTransaction()
{
...
}// A *private* static property gets the current instance.
Connection current
{
get
{
Connection c = CallContext.GetData(threadKey) as Connection;
if (c == null)
{
// This is the only place in the app we need to know where
// connection information comes from. :)
string cnxStr = ...;
c = new Connection(cnxStr);
}
return c;
}
}// The public interface is all static, giving the illusion that there
// is only one connection, when in fact there is one per thread.
static public void BeginTransaction()
{
// Just call the corresponding instance method on "current".
current.beginTransaction();
}
}We couple this with our own custom-written "Thread class" (Thread is sealed so our type is not really a thread, but it has the same interface as a thread so where our code was creating threads we just switched the type to our own) which copies the execution context of the thread that creates it, and we have a wonderfully simple to use solution with a minimum of code redundancy. (The "where do connection info come from" logic was all over the place before, and we had problems knowing when we should clone connections and when we should not, because the method using a connection would sometimes be called as part of a transaction and sometimes without one, sometimes in a thread pr
Nice. You might want to write up an article about this...
I didn't get any requirements for the signature