[CLOSED] DirectMethod heartbeat task and State management

  1. #1

    [CLOSED] DirectMethod heartbeat task and State management

    Hi,

    I'd like to be able to examine the Request object on the server to find out which DirectMethod has initiated it. I'm curious how to approach it. Every page in my application is inherited from the BasePage class, which has the overridden OnInit method. In there, my logic inspects the Session to determine if it's expired or not causing the redirect if needed.
    What I'm trying to accomplish here is to create a little heartbeat task using TaskManager that polls the server every SessionTimeout interval using DirectMethod to see if the Session is still alive. There's a slight logistics problem here. The heartbeat call by itself inadvertently revives the otherwise idle Session extending its validity until at least another heartbeat cycle.

    My thought process is to provide a unique marker for the heartbeat Request so that it can be analyzed in the OnInit. If a Request is NOT initiated by the heartbeat, I can use a custom Session variable, e.g. "LastAccessed", to store the timestamp when it was last accessed. If the Request is indeed initiated by the heartbeat task, I should then check the value of the "LastAccessed" variable and adjust the task interval accordingly. For example, If the last user Request was initiated 12 minutes ago with the SessionTimeout of 20 minutes, the next poll by my heartbeat task should occur in 20-12=8 minutes. If it then detects that the value of the LastAccessed variable hasn't changed, it should invalidate the session and cause the redirect after its return to the client even if the session is technically alive.
    The simplest case occurs when the heartbeat hits the server and the session has truly expired. Then, the logic in OnInit redirects the user to a designated web page.

    Here's the code snippets. Does my logic make sense? Please advise if there's an established pattern to achieve this behavior or if you need more information.

    BasePage.cs
    public partial class BasePage : System.Web.UI.Page
    {
        override protected void OnInit(EventArgs e)
        {
            //initialize our base class (System.Web,UI.Page)
            base.OnInit(e);
    
            //check to see if the Session is null (doesnt exist)
            if (Context.Session != null)
            {
                //check the IsNewSession value, this will tell us if the session has been reset.
                //IsNewSession will also let us know if the users session has timed out
                if (Context.Session.IsNewSession)
                {
                    //now we know it's a new session, so we check to see if a cookie is present
                    string cookie = Request.Headers["Cookie"];
                    //now we determine if there is a cookie does it contains what we're looking for
                    if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))
                    {
                        if (Request.UrlReferrer != null)
                            Response.Redirect(baseURL + "/SessionExpired.aspx");
                    }
                }
                else
                {
                    // Logic to inspect the Request?? object to see if it's initiated by DoHeartbeat()
                    bool isHeartBeat = false;
                    /*
                    NameValueCollection headers = base.Request.Headers;
                    string requestedWith = headers["X-Requested-With"];
                    if (!String.IsNullOrEmpty(requestedWith) && requestedWith.Equals("XMLHttpRequest"))
                        isHeartBeat = true;
                    */
                    if(isHeartBeat)
                    {
                        DateTime lastUpdated = Session["LastAccessed"] as DateTime;
                        // Convert to milliseconds to get the interval when the Heartbeat service should run next time
                        long updatedInterval = DateTime.Now.Ticks - lastUpdated.Ticks;
                        Session["UpdatedInterval"] = updatedInterval;
                    }
                    else
                    {
                        // Set the value of Session["LastAccessed"] because this request is initiated NOT by HeartBeat
                        Session["LastAccessed"]=DateTime.Now;
                    }
                }
            }
        }
    }
    Default.aspx.cs
    // Non-static method to ensure that page lifecycle is followed
    [DirectMethod]
    public long DoHeartbeat()
    {
        long updatedInterval=Convert.ToInt64(Session["UpdatedInterval"]);
        return updatedInterval;
    }
    Default.aspx
    <ext:TaskManager ID="TaskManager1" runat="server">
        <Tasks>
            <ext:Task TaskID="TaskHeartbeat" Interval="120000" AutoRun="true">
                <Listeners>
                    <Update Handler="X.DoHeartbeat({success : function(result){TaskManager1.tasks[0].interval=result;});" />
                </Listeners>
            </ext:Task>
        </Tasks>
    </ext:TaskManager>
    Last edited by Daniil; Sep 21, 2012 at 6:12 AM. Reason: [CLOSED]
  2. #2
    Hi Vadym,

    Thank you for the detailed explanation and the code snippet.

    Quote Originally Posted by vadym.f View Post
    I'd like to be able to examine the Request object on the server to find out which DirectMethod has initiated it.
    If you would look at a DirectMethod request, you will see "__EVENTARGUMENT" with the data you require.

    Example
    <%@ Page Language="C#" %>
     
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <script runat="server">
        protected void Page_Init(object sender, EventArgs e)
        {
            if (X.IsAjaxRequest)
            {
                X.Msg.Alert("Page_Init", this.Request["__EVENTARGUMENT"]).Show();   
            }
        }
    
        [DirectMethod]
        public void TestDirectMethod1()
        {        
        }
    
        [DirectMethod]
        public void TestDirectMethod2()
        {
        }
    
        protected void TestDirectEventHandler(object sender, DirectEventArgs e)
        {
        }
    </script>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Ext.NET Example</title>
    </head>
    <body>
        <form runat="server">
            <ext:ResourceManager runat="server" />
            
            <ext:Button runat="server" Text="Call DirectMethod 1">
                <Listeners>
                    <Click Handler="Ext.net.DirectMethods.TestDirectMethod1();" />
                </Listeners>
            </ext:Button>
    
            <ext:Button runat="server" Text="Call DirectMethod 2">
                <Listeners>
                    <Click Handler="Ext.net.DirectMethods.TestDirectMethod2();" />
                </Listeners>
            </ext:Button>
    
            <ext:Button 
                ID="Button1" 
                runat="server" 
                Text="Call DirectEvent" 
                OnDirectClick="TestDirectEventHandler" />
        </form>
    </body>
    </html>
    Quote Originally Posted by vadym.f View Post
    Here's the code snippets. Does my logic make sense? Please advise if there's an established pattern to achieve this behavior or if you need more information.
    I think it makes sense. I don't know any pattern to achieve this functionality.
  3. #3
    Quote Originally Posted by Daniil View Post
    If you would look at a DirectMethod request, you will see "__EVENTARGUMENT" with the data you require.
    That was the missing gem, many thanks!!

    BTW, somehow I was unable to start a task on the client in the DocumentReady handler. Every time it would throw a client side error. Setting AutoRun to true or false or accessing the task by ID or index didn't seem to matter. What's missing here?

    <ext:ResourceManager ID="ResourceManager1" DisableViewState="true" runat="server"
    	DirectMethodNamespace="X">
    	<Listeners>
    		<DocumentReady Handler="TaskManager1.startTask('Task1');" />
    	</Listeners>
    </ext:ResourceManager>
    
    <ext:TaskManager ID="TaskManager1" runat="server">
    	<Tasks>
    		<ext:Task TaskID="Task1" Interval="10000" AutoRun="false">
    			<Listeners>
    				<Update Handler="alert(1);" />
    			</Listeners>
    		</ext:Task>
    	</Tasks>
    </ext:TaskManager>
  4. #4
    Quote Originally Posted by vadym.f View Post
    BTW, somehow I was unable to start a task on the client in the DocumentReady handler. Every time it would throw a client side error.
    The TaskManager tasks are not rendered yet at that moment. The following works:

    Example
    <DocumentReady Handler="TaskManager1.startTask.defer(100, TaskManager1, ['Task1']);" />
    Quote Originally Posted by vadym.f View Post
    Setting AutoRun to true or false or accessing the task by ID or index didn't seem to matter. What's missing here?
    Setting
    AutoRun="true"
    works for me. Do not you remove the DocumentReady listener when set AutoRun to true?
  5. #5
    Thanks! What's the preferred way to start a task, on the server or on the client?
  6. #6
    Generally, it can depends on requirements.

    A main rule is - avoid AJAX if you really do not need it, i.e. if something can be done on client via JavaScript, it is the best choice to do it.

    Hope this answers your question.
  7. #7
    Thanks Daniil! Please close this thread down.

Similar Threads

  1. [CLOSED] Session management problem in IE8
    By vadym.f in forum 1.x Legacy Premium Help
    Replies: 9
    Last Post: Jun 13, 2012, 8:44 PM
  2. Concerned about memory management
    By dbassett74 in forum 1.x Help
    Replies: 3
    Last Post: Nov 16, 2009, 4:33 PM
  3. Print job management for web applications
    By Nime in forum Open Discussions
    Replies: 1
    Last Post: Aug 04, 2009, 10:12 AM
  4. [CLOSED] Page_Load bug and session state management
    By jsemple in forum 1.x Legacy Premium Help
    Replies: 1
    Last Post: Jun 24, 2009, 5:30 PM
  5. Window management best practices
    By dbassett74 in forum 1.x Help
    Replies: 1
    Last Post: Apr 20, 2009, 8:24 PM

Posting Permissions