Answered by:
Session context with background threads

Question
-
User-891142405 posted
Hello,
I have an ASP web service handler that has public methods for the clients. Theses methods contain long lasting calculations and remote procedure calls.
I am searching for a possibility that the clients of my web service handler make a service call which returns a unique id immediately which is generated in my server. Meanwhile a background thread handles the actual request asynchronally. When the background thread finishes, it saves the calculation result in the user session. The clients can call another method with the id from the last response (like a polling mechanism). The server looks in the session if there is a key with this id. If the key in the session is available, the server returns the calculation result.
So far the concept.
The problem is, that the session context is null when my background thread wants to access the session context. Do you have any idea how I can solve this problem? Is there a possibility that the session is available for my asynchronous thread?
Regards,
TMK
Wednesday, April 22, 2009 12:58 PM
Answers
-
User-318989783 posted
I used both methods session and the HTTPRuntime.Cache and it works witht he session though you need to explicitly add the attribute [WebMethod(EnableSession = true)]
and on the client side you need to add a container for the cookie that the session sends, usually this is handled by the browser.[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
private string _tmp;
public string Tmp
{
get { return _tmp; }
set { _tmp = value; }
}
[WebMethod(EnableSession = true)]
public string startCalculate()
{
Session["1234"] = "Empty";
calculate("1234");
return Session["1234"].ToString();
}
[WebMethod(EnableSession = true)]
public string retrieveValue(string ID)
{
string tmp = "";
try{
tmp = Session[ID].ToString();
}
catch(Exception ex)
{
tmp = "Searching!" + ex.Message;
}
return tmp;
}
[WebMethod(EnableSession = true)]
private void calculate(string Id)
{
Thread th = new Thread(
delegate()
{
Thread.Sleep(1500);
Tmp = "something";
});
th.IsBackground = true;
th.Start();
th.Join();
Session[Id] = Tmp;
}
}Using the HTTP Runtime Cache
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class WebService1 : System.Web.Services.WebService
{
private string _tmp;
public string Tmp
{
get { return _tmp; }
set { _tmp = value; }
}
[WebMethod]
public string startCalculate()
{
string key = Guid.NewGuid().ToString();
insertCacheObject(key, "Empty");
calculate(key);
return key;
}
[WebMethod]
public string retrieveValue(string key)
{
string tmp = "";
try
{
tmp = HttpRuntime.Cache.Get(key).ToString();
}
catch (Exception ex)
{
tmp = "Searching!" + ex.Message;
}
return tmp;
}
[WebMethod]
private void calculate(string key)
{
Thread th = new Thread(
delegate()
{
Thread.Sleep(10000);
Tmp = "something";
insertCacheObject(key, Tmp);
});
th.IsBackground = true;
th.Start();
}
private void insertCacheObject(string key,string ver)
{
HttpRuntime.Cache.Insert(
key
,(object)ver
, null
, DateTime.Now.AddSeconds( 15 )
, Cache.NoSlidingExpiration );
}
}I am very curious to know what you did to solve this issue!
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Saturday, April 25, 2009 5:19 PM
All replies
-
User-318989783 posted
I think your session is lost as soon as the conenction is closed, you will need to persist the result in another form why not use a database or a flat file instead of a session object to persist the result. You can create an empty row in the database and return the id, let your background thread complete its task and store the result in the same row. When the client makes a requst using the id you can return whatever result it is. This will be more robust than actually relying on a session to save your result E.g. your webserver was restarted etc
Thursday, April 23, 2009 1:39 AM -
User-891142405 posted
Thanks for your answer! Your solution will work, I thought about such a concept, too. But the negative point in my view is, that the access to the session is faster that to a flat file or accessing a database (perhaps on another host). My session data won't be lost when a web server restarts because I am using a state server. But that is not that important poin for me, so it won't be very bad if a session could be lost in case of a server restart. For my application the performance is more important. So I hoped that there is a possibility to give the background thread access to the sesion in any way. Perhaps some of the other users here can give us a hint if this problem can be solved in a better way.
Thanks,
TMK
Thursday, April 23, 2009 2:22 AM -
User-318989783 posted
I thought about it after I replied it isnt really crucial data so reliability isnt a criteria I guess. If performance is your issue and you want to persist the results to memory why dont you write your result object to the cache you can still retrieve it from there using the id and it will still be fast .
You will need to use delegates to access data outside your background thread.
Thursday, April 23, 2009 2:37 AM -
User-891142405 posted
Yes, the cache could be a good choice! But in my application scenario, it can be possible that I have more than one IIS behind a load balancer. As far as I know, the cache is not shared between IIS servers. Is there a possible solution that the caching scenario works with more servers?
Thanks for your opinion!
TMK
Thursday, April 23, 2009 2:47 AM -
User-318989783 posted
This could help answer your question.
http://www.15seconds.com/issue/071012.htm
Thursday, April 23, 2009 2:49 AM -
User-891142405 posted
Thanks for the link! One further question: Can I use the Cache only in aspx pages or is it also posible to use the Cache in HttpHandlers?
Thursday, April 23, 2009 3:05 AM -
User-318989783 posted
You should be able to see this post
http://forums.asp.net/p/1107314/1697001.aspx
Thursday, April 23, 2009 4:45 AM -
User-891142405 posted
Hmmm I did a little research in the meanwhile. It looks like I cannot use the cache, too. The Cache is attached to the HttpContext.Current.Cache. But my background thread lives longer than my http request. After the server has send the response to the client, the HttpContext is destroyed. So my still working background thread is not able to write to the Cache or Session :(.
Perhaps I really have to implement a solution where the background thread writes the result to a database...
Thursday, April 23, 2009 4:55 AM -
User-318989783 posted
I don't think that is correct you should be able to access the cache from outside threads, the cache is global there aren't even locks on the cache for performance reasons. Could I see your code implementation for accessing the cache from your background thread?
My simple reasoning for the above would be user A could request some data that is cached on retrieval. A user B at a later time may request the same data that will be retrieved from the cache they are both on different contexts.
Again to save time I would just use the database approach and cache the data if you have more time try the above.
Ok I tried the following and it works using sessions again I haven't really run a very long task but try increasing the session time out if that is an issue
namespace WebService1
{
/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
public string startCalculate()
{
calculate("1234");
return "1234";
}
[WebMethod(EnableSession = true)]
public string retrieveValue(string ID)
{
string tmp = "";
try{
tmp = Session[ID].ToString();
}
catch
{
tmp = "Not found!";
}
return tmp;
}
private void calculate(string Id)
{
Thread th = new Thread(
delegate()
{
Session[Id] = (object)"something";
});
th.IsBackground = true;
th.Start();
}
}
}Thursday, April 23, 2009 5:14 AM -
User-891142405 posted
If the thread needs a longer time, the session is null.
Just try it:
private void calculate(string Id)
{
Thread th = new Thread(
delegate()
{
Thread.Sleep(4000);
Session[Id] = (object)"something";
});
th.IsBackground = true;
th.Start();
}Thursday, April 23, 2009 7:04 AM -
User-318989783 posted
Did you try increasing the session time out ? I am going to head out soon but will try this again its a really interesting problem
Thursday, April 23, 2009 7:12 AM -
User-891142405 posted
No, as far as I know is the session timeout the value how long the user session lifes without an user interaction. After this value, the session is destroyed. Unfortunately it seems that the session timeout has does not influence the threading problem...
Thursday, April 23, 2009 8:50 AM -
User-458471961 posted
Can't you use a static / singleton class to achieve this functionality..? you need to have thread synchronization in this case...
Thanks,
Saravanan
Thursday, April 23, 2009 9:11 AM -
User-891142405 posted
I experiented with a static variable yesterday but this was a mess... Perhaps you have a working solution and can post it here?
Thursday, April 23, 2009 9:23 AM -
User-318989783 posted
Try this it work, youll need to wait till the thread completes execution
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
private string _tmp;
public string Tmp
{
get { return _tmp; }
set { _tmp = value; }
}
[WebMethod(EnableSession = true)]
public string startCalculate()
{
Session["1234"] = "Empty";
calculate("1234");
return "1234";
}
[WebMethod(EnableSession = true)]
public string retrieveValue(string ID)
{
string tmp = "";
try{
tmp = Session[ID].ToString();
}
catch
{
tmp = "Not found!";
}
return tmp;
}
private void calculate(string Id)
{
Thread th = new Thread(
delegate()
{
Thread.Sleep(30);
Tmp = "something";
});
th.IsBackground = true;
th.Start();
th.Join();
Session[Id] = Tmp;
}
}
Thursday, April 23, 2009 2:10 PM -
User33617324 posted
Use HttpRuntime.Cache store the result with the generated unique id as the key.
Thursday, April 23, 2009 10:36 PM -
User-891142405 posted
HttpRuntime.Cache seems to work. That surprises me a little bit because System.Web.Caching.Cache did not work at all in my scenario.
Can you explain what's the diference between these two Cache classes and does HttpRuntime.Cache works also in a web farm or web garden?
Thanks,
TMK
Friday, April 24, 2009 2:35 AM -
User-318989783 posted
I used both methods session and the HTTPRuntime.Cache and it works witht he session though you need to explicitly add the attribute [WebMethod(EnableSession = true)]
and on the client side you need to add a container for the cookie that the session sends, usually this is handled by the browser.[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
private string _tmp;
public string Tmp
{
get { return _tmp; }
set { _tmp = value; }
}
[WebMethod(EnableSession = true)]
public string startCalculate()
{
Session["1234"] = "Empty";
calculate("1234");
return Session["1234"].ToString();
}
[WebMethod(EnableSession = true)]
public string retrieveValue(string ID)
{
string tmp = "";
try{
tmp = Session[ID].ToString();
}
catch(Exception ex)
{
tmp = "Searching!" + ex.Message;
}
return tmp;
}
[WebMethod(EnableSession = true)]
private void calculate(string Id)
{
Thread th = new Thread(
delegate()
{
Thread.Sleep(1500);
Tmp = "something";
});
th.IsBackground = true;
th.Start();
th.Join();
Session[Id] = Tmp;
}
}Using the HTTP Runtime Cache
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class WebService1 : System.Web.Services.WebService
{
private string _tmp;
public string Tmp
{
get { return _tmp; }
set { _tmp = value; }
}
[WebMethod]
public string startCalculate()
{
string key = Guid.NewGuid().ToString();
insertCacheObject(key, "Empty");
calculate(key);
return key;
}
[WebMethod]
public string retrieveValue(string key)
{
string tmp = "";
try
{
tmp = HttpRuntime.Cache.Get(key).ToString();
}
catch (Exception ex)
{
tmp = "Searching!" + ex.Message;
}
return tmp;
}
[WebMethod]
private void calculate(string key)
{
Thread th = new Thread(
delegate()
{
Thread.Sleep(10000);
Tmp = "something";
insertCacheObject(key, Tmp);
});
th.IsBackground = true;
th.Start();
}
private void insertCacheObject(string key,string ver)
{
HttpRuntime.Cache.Insert(
key
,(object)ver
, null
, DateTime.Now.AddSeconds( 15 )
, Cache.NoSlidingExpiration );
}
}I am very curious to know what you did to solve this issue!
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Saturday, April 25, 2009 5:19 PM -
User-751748719 posted
maintain a copy of the session in memory and pass it down to your thread
Tuesday, February 23, 2010 9:56 AM