barbajoe
barbajoe

Reputation: 547

site wide variables per user

I have an MVC4 site that needs to maintain some information while (and ONLY while) the user is logged in. For example, once the user logs in, I get a 'user token' back that allows me access to several off site services.

I've tried two different approaches. The first was to use a public static class that accesses the user session. However, after reading up on static classes, I'm hesitant to use them. According to what I'm reading, static classes should only be used for read only objects, and I wasn't using it that way. Although the site site did seem to be working fine with a limited number of users (currently there's 10).

(If someone would like to explain to me why this is a bad idea in MVC4, please tell me and/or link to an article)

public class SessionAccessorClasses
{
    public const string SessionAccessorSessionVariablesString = "_SessionAccessorSessionVariables";
    public static SessionAccessorModel SessionVariables
    {
        get { return System.Web.HttpContext.Current.Session != null ? (SessionAccessorModel)System.Web.HttpContext.Current.Session[SessionAccessorSessionVariablesString] : null; }
        set { System.Web.HttpContext.Current.Session.Add(SessionAccessorSessionVariablesString, value); }
    }
}

My second (and current) approach is to use Session variables and access them using a globally available class.

public class SessionAccessorClasses
{
    private const string SessionAccessorSessionVariablesString = "_SessionAccessorSessionVariables";
    public SessionAccessorModel GetSessionVariables()
    {
        return System.Web.HttpContext.Current.Session != null ? (SessionAccessorModel)System.Web.HttpContext.Current.Session[SessionAccessorSessionVariablesString] : null;
    }
    public void SetSessionVariables(SessionAccessorModel value)
    {
        System.Web.HttpContext.Current.Session.Add(SessionAccessorSessionVariablesString, value);
    }
    public void ClearSessionVariables()
    {
        System.Web.HttpContext.Current.Session.Remove(SessionAccessorSessionVariablesString);
    }
}

This works fine, but I hesitate to call it good is because I don't fully understand why the public static class was such a bad idea, and because I now have to instantiate my new class at the beginning of nearly every function, and call the Set/Update function at the end of every function; which feels wrong somehow.

So first, since my original static class was accessing the users session, is it really that bad?

Second, is my second class a more appropriate way of doing things? Can you suggest improvements?

Third, if nothing else, can you give me the positive/negative aspects of doing it either way?

Upvotes: 1

Views: 2902

Answers (1)

Erik Philips
Erik Philips

Reputation: 54618

You want to use Session in ASP.net. It was created for the purpose you describe.

ASP.NET session state enables you to store and retrieve values for a user as the user navigates ASP.NET pages in a Web application. HTTP is a stateless protocol. This means that a Web server treats each HTTP request for a page as an independent request. The server retains no knowledge of variable values that were used during previous requests. ASP.NET session state identifies requests from the same browser during a limited time window as a session, and provides a way to persist variable values for the duration of that session. By default, ASP.NET session state is enabled for all ASP.NET applications.

I'm a fan of strongly-typed reusable session variables, so I wrote the following extensions to store whatever variables you want to create without the need to constantly remember magic strings.

public static class SessionExtensions
{
    public static bool TryGetValue<T>(this HttpSessionStateBase session, out T value) 
      where T : class
    {
        var name = typeof(T).FullName;

        value = session[name] as T;

        var result = value != null;

        return result;
    }

    public static void SetValue<T>(this HttpSessionStateBase session, T value)
    {
        var name = typeof(T).FullName;

        session[name] = value;
    }

    public static void RemoveValue<T>(this HttpSessionStateBase session)
    {
        var name = typeof(T).FullName;

        session[name] = null;
    }

    public static bool ValueExists(this HttpSessionStateBase session, Type objectType)
    {
        var name = objectType.FullName;

        var result = session[name] != null;

        return result;
    }
}

So if you have a class:

public MyClass
{
  public int MyInt { get; set; }
}

You can store it by simply:

Session.SetValue(MyClass);

that needs to maintain some information while (and ONLY while) the user is logged in.

These methods could be updated a few ways to fulfill this requirement. Here is one way:

public static bool TryGetAuthenticatedValue<T>(this HttpSessionStateBase session, 
  out T value) 
  where T : class
{
    value = null;

    if (HttpContext.Current.User != null
        && HttpContext.Current.User.Identity != null
        && HttpContext.Current.User.IsAuthenticated)
    {
      var name = typeof(T).FullName;

      value = session[name] as T;
    }

    var result = value != null;

    return result;
}       

I would also recommend that whatever classes you store in session, be serializable. That is to say it has a parameterless constructor and marked as [Serializable].

Upvotes: 3

Related Questions