Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent expiration of individual sessions based on custom conditions?

A website I am working on is very data centric. Some reports take more than an hour to complete. Whenever a user submits a request for a report, a new thread is created which generates the report. The user is then redirected to a page which says that the report in progress, and to please refresh to download the report. If the user again refreshes the page and the report is still in progress, the same message is shown; otherwise a download link is provided.

All report/user relations are saved in the application variable. That works fine, except when the user is inactive for more than 20 min (while the report is being processed), and then the user is logged out; if the user logs in again, the report can still be downloaded.

I do not want to increase the session expiration time, but I need to stop the expiration if the user has something going in background, like a report being processed.

In Session_End I am able to retrieve the the userid and match it in Application["work"] to see the user has pending work or not.

However, I am clueless as to how I can defer the session end in the above case?


Edit: Every one has suggested as a workaround from 'maintaining a contact' to 'using query string'. 'Maintaining the contact' looked the most promising to me but it fails in the following scenarios: a. When browser is closed/computed goes in standby mode during lunch, etc. b. When user goes to another non-asp.net section (it's a legacy site).

Isn't It possible to cancel the Session_End event itself?

like image 977
Ratna Avatar asked Apr 01 '13 11:04

Ratna


People also ask

Where do you configure your session expiration time?

An organization owner or administrator can change the session expiration in the General Organization Settings section of the Application Management products' common settings. To change the length of time a user can remain logged into the product before the session times out, click Edit Session Expiration.

What is automatic session expiration?

Session Expire itself means that your web page has lost its connectivity to internet and it is no more active page(user data also expired) so it cannot re-direct to login page itself. Once a request is made to site again, it will automatically redirect request to login page.

What causes a session to expire?

If your Internet connection is unstable, periodically disconnecting and reconnecting, it can cause a website session to expire. When the Internet connection is lost the website connection can be terminated, resulting in a session expired message if you try to access any page after the Internet reconnects.


1 Answers

The short answer

There is currently (that I know of) no simple way to extend the life of a single ASP.NET session. There is one possible solution: use a custom Session-State Store Provider!


The long answer

First things first: Start with something that is already built! Use the sample Session-State Store Provider (and its tutorial) provided by Microsoft. This sample Session-State Store Provider uses Microsoft Access as its back end; although, because it uses ODBC connections, you can have virtually any database back end supported through your installed ODBC drivers.

This sample Session-State Store Provider is simply a custom version of what ASP.NET uses internally (with the exception that ASP.NET's runs in-memory).


Secondly: Let's prepare the Access Database requirements, and the configuration.

Create the table as specified in the tutorial and in the comments of the file:

CREATE TABLE Sessions
(
    SessionId       Text(80)  NOT NULL,
    ApplicationName Text(255) NOT NULL,
    Created         DateTime  NOT NULL,
    Expires         DateTime  NOT NULL,
    LockDate        DateTime  NOT NULL,
    LockId          Integer   NOT NULL,
    Timeout         Integer   NOT NULL,
    Locked          YesNo     NOT NULL,
    SessionItems    Memo,
    Flags           Integer   NOT NULL,

    CONSTRAINT PKSessions PRIMARY KEY (SessionId, ApplicationName)
)

NOTE: If you want to use SQL Server, simply replace Text(...) with varchar(...), YesNo with bit, and Memo with varchar(MAX).

Add/update your web.config with the following (you can use connectionstrings.com to help you generate a connection string):

<configuration>
    <connectionStrings>
        <add name="OdbcSessionServices" connectionString="DSN=SessionState;" />
    </connectionStrings>

    <system.web>
        <sessionState 
                cookieless="true"
                regenerateExpiredSessionId="true"
                mode="Custom"
                customProvider="OdbcSessionProvider">
            <providers>
                <add name="OdbcSessionProvider"
                        type="Samples.AspNet.Session.OdbcSessionStateStore"
                        connectionStringName="OdbcSessionServices"
                        writeExceptionsToEventLog="false" />
            </providers>
        </sessionState>
    </system.web>
</configuration>

Third: Adding a function that will extend for more than the specified Timeout.

Make a copy of the ResetItemTimeout function, and name it ResetItemTimeout2:

var ExtendedTotalMinutes = 2 * 60; // hours * minutes

public override void ResetItemTimeout2(HttpContext context, string id)
{
    OdbcConnection conn = new OdbcConnection(connectionString);
    OdbcCommand cmd = 
        new OdbcCommand("UPDATE Sessions SET Expires = ? " +
            "WHERE SessionId = ? AND ApplicationName = ?", conn);
    cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value 
        = DateTime.Now.AddMinutes(ExtendedTotalMinutes); // IMPORTANT!! Set your total expiration time.
    cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id;
    cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName;

    try
    {
        conn.Open();

        cmd.ExecuteNonQuery();
    }
    catch (OdbcException e)
    {
        if (WriteExceptionsToEventLog)
        {
            WriteToEventLog(e, "ResetItemTimeout");
            throw new ProviderException(exceptionMessage);
        }
        else
            throw e;
    }
    finally
    {
        conn.Close();
    }
}

Fourth: Supporting the extension of a single ASP.NET Session!

Whenever you need to extend a session, call the ResetItemTimeout function as follows:

using Samples.AspNet.Session;

// from inside a User Control or Page
OdbcSessionStateStore.ResetItemTimeout2(this.Context, this.Session.SessionID);

// --or--

// from anywhere else
OdbcSessionStateStore.ResetItemTimeout2(System.Web.HttpContext.Current, System.Web.HttpContext.Current.Session.SessionID);

Footnotes

  1. Read the comments on the page with the sample Session-State Store Provider;

    • There is one potential good entry about a Mistake in GetSessionStoreItem when using GetItem.

    • Another good one is that Timestamps should be UTC.

  2. There are obvious performance/maintainability improvements that could be done (especially with having duplicate code in ResetItemTimeout and ResetItemTimeout2).

  3. I have not tested this code!


Edits

  • I realized I missed the part where you want to extend more than the Timeout - answer has been fully updated.
  • Added footnotes section.
like image 130
Jesse Avatar answered Oct 19 '22 23:10

Jesse