PositiveGuy
PositiveGuy

Reputation: 47733

Persisting Session to DB

My architect is wondering why we need to persist each user's session to the DB instead of just using cookies. I have never seen anyone use just cookies.

Usually I hold the Session Id in a cookie then use it to perform CRUDS on the session record keyed off the ID.

I mean I don't see how you can do session state without in proc. I've always done session state via a custom table holding routine fields like IsLoggedIn, IsClosed, IsNew, IPAddress, Browser, and so on.

Has anyone done session state on an e-commerce site without persisting it in a DB?

UPDATED

So here is kinda how we did things at another place I worked for an e-commerce site that got 500+ page hits a month:

public USession CreateNewSession(int userID)
{
    string ipAddress = GetCurrentRequestIPAddress(context.Request);

    USession newSession = USession.NewSession();
    newSession.IpAddress = ipAddress;
    newSession.UserID = customerID;
    newSession.Browser = context.Request.UserAgent ?? string.Empty;

    if (context.Request.UrlReferrer != null)
    newSession.Referer = context.Request.UrlReferrer.ToString();
    else
    newSession.Referer = string.Empty;

    InsertSession(newSession);

    return newSession;
}



public USession CreateNewSession(int userID)
{
    string ipAddress = GetCurrentRequestIPAddress(context.Request);

    USession newSession = USession.NewSession();
    newSession.IpAddress = ipAddress;
    newSession.UserID = customerID;
    newSession.Browser = context.Request.UserAgent ?? string.Empty;

    if (context.Request.UrlReferrer != null)
         newSession.Referer = context.Request.UrlReferrer.ToString();
    else
         newSession.Referer = string.Empty;

    InsertSession(newSession);

    return newSession;
}



public USession GetSession()
{
    // existing sessionId this session?
    HttpCookie cookie = context.Request.Cookies["usessionId"];

    if (cookie == null || string.IsNullOrEmpty(cookie.Value))
    session = CreateNewSession(0);
    else
    {
        string sessionID = cookie.Value;

        session = GetSession(sessionID);

        if (session == null) 
            session = CreateNewSession(0);
        else if (session.IsClosed > 0) 
            session = CreateNewSession(session.UserID);
    }

    if (session.LastAccessed < DateTime.Now.AddHours(-1)) session.LoggedIn = false;

    if (session.LastDestination.Equals("lesson"))
        session.LastDestPageDestinationID = ContextValue(context, "lessonid");
    else
        session.LastDestPageDestinationID = 0;

    if (session.IsNew) session.FirstDestination = session.LastDestination;

    SaveSession();

    return session;
}



private void SaveSession()
{
    session.LastAccess = DateTime.Now;
    session.LastDest = string.Empty;

    db.UpdateSession(session);

    if (!cookieIsSet)
    {
        // add a session cookie for this current session
        HttpCookie cookie = CreateSessionCookie("usessionId", session.SessionID, 365);

        if (session.LastDest.Equals("logout", StringComparison.OrdinalIgnoreCase))
            cookie.Value = string.Empty;

        if (session.LastDest.Equals("lessonOrder")) return;

        context.Response.SetCookie(cookie);
    }
}


internal void UpdateSession(USession s)
{
    using (ourConnection conn = CreateConnection("UpdateSession"))
    {
        conn.CommandText = @"update csession set
            closed = @closed,
            userID = @customerID,
            lastAccess = @lastAccess,
            lastDestination = @lastDest,
                        orderId = @OrderId,
            IsloggedIn = @isLoggedIn;

        conn.AddParam("@id", s.Id);
        conn.AddParam("@closed", s.Closed);
        conn.AddParam("@userID", s.UserID);
        conn.AddParam("@lastAccess", s.LastAccess);
        conn.AddParam("@firstDestination", s.FirstDestination);
        conn.AddParam("@lastDestination", s.LastDestination);
        conn.AddParam("@isLoggedIn", s.IsLoggedIn);
        conn.AddParam("@orderID", s.OrderID);

        try
        {
            conn.ExecuteNonQuery();

        }
        catch (Exception ex)
        {
            LogException(ex);
        }
    }
}


public HttpCookie CreateSessionCookie(string cookieValue, string uSessionID, double daysTillExpiration)
{
    HttpCookie cookie = new HttpCookie("usessionid", uSessionID);
    cookie.Expires = DateTime.Now.AddDays(daysTillExpiration);
    cookie.Path = "/";

    return cookie;
}

So we'd work with the USession custom object in memory throughout our code for checking for loggedIn, to force close their session, and all sorts of stuff based on their current session.

Also in our Application_Error in global.asax we would log the current sessionId for tracking purposes on error.

HttpCookie cookie = Request.Cookies["usessionid"];
if (cookie != null)
{
    logger.Variables = "<b>uSessionID:</b> " + cookie.Value;

    if (cookie.Value.Length > 0)
        logger.USessionID = GetUSessionID(cookie.Value);
}

Upvotes: 0

Views: 463

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038710

The ASP.NET session has 3 possible states:

  • Off (my preferred) - don't use any session at all
  • InProc - the session is stored in the memory of the web server. Fast, but not convinient if you are running in a web farm because each node of the web farm will have a different copy of the session and you might get conflicts.
  • Out-of-Proc - the session is stored in memory of a specially dedicated server running the ASP.NET Session state Windows service. Good for webfarms scenarios but not reliable enough as the session is still persisted in the memory of some server which might not survive crashes.
  • SQL Server - the session is persisted in SQL server. Very reliable and suitable for web farms. Problem is with performance. It will be slower than the previous modes as the session is now persisted in the database.

The 3 modes are covered in depth in the following article.

The mode you choose is configured in web.config and it is completely transparent to your code in which you simply use the Session["someKey"] to work with the session, it's just the underlying storage mechanism that differs.

Upvotes: 2

Related Questions