Using session wrapper for accessing session data When users log in to our website, we store some information in a session to retrieve it across the site. We created a few wrappers to help with data retrieval/storage to lessen duplication of code.

I'm trying to redesign it as I don't like how the UserModel is written. I believe it's dangerous with the static properties, but so far it's been working.

However...

While we haven't noticed any issues, recently someone use something very similar to our code (slightly modified) for another project and had about 20+ people log in at the same time. Some users saw other user's information instead of their own. This brought a huge concern on the original code (below) and would like to get any feedback on how to make it "better" or avoid the same issue they ran into (if it even will happen).

I searched/read around Google/Stack Overflow about the possible issue being at our static method wrappers.

UserModel.cs

public class User {
    private const Boolean UseSessionAsDataStore = true;

    protected const String kUserId = "UserId";
    protected const String kUserName = "UserName";
    protected const String kUserEmail = "UserEmail";

    public static Int32 UserId {
        get { return GetInt32Value(kUserId); }
        set { SaveValue(kUserId, value.ToString()); }
    }

    public static String UserName {
        get { return GetStringValue(kUserName); }
        set { SaveValue(kUserName, value); }
    }

    public static String UserEmail {
        get { return GetStringValue(kUserEmail); }
        set { SaveValue(kUserEmail, value); }
    }

    protected static void SaveValue(String key, String value) {
        UseSessionAsDataStore ?
        SessionHelper.SaveSessionValue(key, value) :
        CookieHelper.SaveCookieValue(key, value);
    }

    protected static void GetStringValue(String key) {
        UseSessionAsDataStore ? SessionHelper.GetSessionStringValue(key) : CookieHelper.GetCookieStringValue(key);
    }

    protected static void GetInt32Value(String key) {
        UseSessionAsDataStore ? SessionHelper.GetSessionInt32Value(key) : CookieHelper.GetCookieInt32Value(key);
    }
}


UserLoginModel.cs

public class UserLoginModel {
    AssignUser (Int32 userId, String userName, String userEmail) {
        UserModel.UserId = userId;
        UserModel.UserName = userName;
        UserModel.UserEmail = userEmail;
    }
}


SessionHelper.cs

(won't provide CookieModel.cs as it's not the issue in question)

public class SessionHelper {
    public static void SaveSessionValue(String key, String value) {
        HttpContext.Current.Session.Add(key, value);
    }

    public static String GetSessionStringValue(String key) {
        if (HttpContext.Current.Session == null || HttpContext.Current.Session[key] == null) { return null; }
        return HttpContext.Current.Session[key] != null ? HttpContext.Current.Session[key].ToString() : String.Empty;
    }

    public static Int32 GetSessionInt32Value(String key) {
        if (HttpContext.Current.Session == null || HttpContext.Current.Session[key] == null) { return 0; }
        Int32 value;
        Int32.TryParse(HttpContext.Current.Session[key].ToString(), out value);
        return value;
    }
}


LoginPage

/* try to log in user and return user data */
...
if (loginSuccessful) {
    UserLoginModel.AssignUser(userId, userName, userEmail);
}
...


MainPage

&lt;html&gt;
    &lt;body&gt;
        Hello &lt;%=UserModel.UserName %&gt;!
    &lt;/body&gt;
&lt;/html&gt;
...


I have a feeling that this code has the potential to share session data between 2 users, although we have yet to realize it, even with about 5 simultaneous logins.
Do not use Hungarian notation for constants, keep it in PascalCase. If you like to differentiate the names from the properties you can name in form of {PropertyName}Key, like UserIdKey.
Do prefer .net aliases over the full type name, like Int32 -> int, String -> string.
Avoid repetition of word, like User.UserId and SessionHelper.GetSession.... Unless you are worried about mixed up with the foreign key in your DTO, but it is not the case here.
UserModel (if it is User, that is fine)(you weren't really consistent with the code) should be renamed to CurrentUser :

// which one makes more sense ?
UserModel.Name = userName;
CurrentUser.Name = userName;

HttpContext.Current.Session shows up quite frequently in SessionHelper, you could use a property to shorten it :

private static HttpSessionState CurrentSession
{
    get { return HttpContext.Current.Session; }
}





The SessionHelper class : 

public class SessionHelper
{
    private static HttpSessionState Session
    {
        get { return HttpContext.Current.Session; }
    }

    public void SaveValue(string key, string value)
    {
        Session.Add(key, value);
    }
    public static string GetStringValue(string key)
    {
        if (Session == null || Session[key] == null)
            return null;

        return HttpContext.Current.Session[key].ToString();
    }
    public static int GetIntValue(string key)
    {
        if (Session == null || Session[key] == null)
            return 0;

        int result;
        return int.TryParse(Session[key].ToString(), out result) ? result : 0;
    }
}


If you can get your hand on C# 6, consider this version :

public class SessionHelper_c6
{
    private static HttpSessionState Session =&gt; HttpContext.Current.Session;

    public void SaveValue(string key, string value)
    {
        Session.Add(key, value);
    }
    public static string GetStringValue(string key)
    {
        return Session?[key]?.ToString() ?? null;
    }
    public static int GetIntValue(string key)
    {
        var value = Session?[key]?.ToString() ?? null;
        int result;
        return value != null &amp;&amp; int.TryParse(value, out result) ? result : 0;
    }
}