views:

241

answers:

1

Hi all,

I would like to use Proxy pattern for Session handling.

In my session proxy class I have something like that:

public static class SessionProxy
{
    private const string ThemeNameSessionName = "ThemeName";
    private const string PasswordExpirationDaysSessionNam = "PasswordExpirationDays";

    ///     
    /// Gets or sets theme name.    
    ///  
    public static string ThemeName
    {
        get
        {
            if (Session[ThemeNameSessionName] == null) 
            { 
                return String.Empty; 
            }

            return (string)Session[ThemeNameSessionName];
        }

        set
        {
            Session[ThemeNameSessionName] = value; 
        }
    }

    /// 
    /// Gets or sets how many days to password expiration.
    ///     
    public static int PasswordExpirationDays
    {
        get
        {            
            return Convert.ToInt32(Session[PasswordExpirationDaysSessionNam]);
        }

        set
        {
            Session[PasswordExpirationDaysSessionNam] = value; 
        }
    }
}

so I use it in my app as:

SessionProxy.ThemeName = "Default";
SessionProxy.PasswordExpirationDays = 5;

With this piece of code I have strongly typed sessions mechanism but.. How to remove session without using string literals (like

Session.Remove("ThemeName")
). In case of strings I can add to my Properties:

        set
        {
if (String.IsNullOrEmpty(value))
{
  Session.Remove(ThemeNameSessionName);
}
else
{
            Session[ThemeNameSessionName] = value; 
}
        }

but in case of other types (int, long, datetime etc.) I can't use null (I don't want to use nullable types).

Can you advice me the best solution of this problem? The perfect one will be something like that if possible:

Session.Remove([some magic here]SessionProxy.ThemeName[/magic]);

And one thing yet, I need it in .NET 2.0 (though soulution for .NET 3.5 also will be interesting). Thank you and Greetz

A: 

Firstly, I would say that the last line of code that you quoted:

Session.Remove([some magic here]SessionProxy.ThemeName[/magic]);

Should really read something like:

SessionProxy.Remove([some magic here]SessionProxy.ThemeName[/magic]);

Since this is all about the proxy pattern, I'd think you'd want to continue to access the Session object via the proxy class even when removing items from the Session rather than accessing the Session object directly (thereby negating some of the usefulness of the proxy class!) Not sure if the above is just a typo, but thought I'd point it out just in case.

To answer your question, one relatively simple way of achieving this is to replace your private string constants inside your proxy class with an enumeration of all of the session variable names that you'd like to define.

For example, altering your code from above:

public static class SessionProxy
{
    public enum SessionProxyVars {
        ThemeName,
        PasswordExpirationDays
    }

    public static string ThemeName {
        get { 
            if (HttpContext.Current.Session[SessionProxyVars.ThemeName.ToString()] == null) {
                return String.Empty;
            }
            return (string)HttpContext.Current.Session[SessionProxyVars.ThemeName.ToString()];
        }
        set {
            HttpContext.Current.Session[SessionProxyVars.ThemeName.ToString()] = value;
        }
    }

    public static int PasswordExpirationDays {
        get {
            return Convert.ToInt32(HttpContext.Current.Session[SessionProxyVars.PasswordExpirationDays.ToString()]);
        }
        set {
            HttpContext.Current.Session[SessionProxyVars.PasswordExpirationDays.ToString()] = value;
        }
    }

    public static void Remove(SessionProxyVars vartoremove) {
        HttpContext.Current.Session.Remove(vartoremove.ToString());
    }
}

Note that I've added a Remove method that takes a SessionProxyVars parameter.

Some simple code showing this in use:

protected void Page_Load(object sender, EventArgs e)
    {
        SessionProxy.ThemeName = "MyLovelyTheme";
        SessionProxy.PasswordExpirationDays = 3;
        Response.Write("<br/><br/>");
        foreach (string sesskey in HttpContext.Current.Session.Keys) {
            Response.Write(sesskey + ": " + HttpContext.Current.Session[sesskey].ToString());
            Response.Write("<br/>");
        }
        SessionProxy.Remove(SessionProxy.SessionProxyVars.ThemeName);
        Response.Write("<br/><br/>");
        // Enumerate the keys/values of the "real" session to prove it's gone!
        foreach (string sesskey in HttpContext.Current.Session.Keys) {
            Response.Write(sesskey + ": " + HttpContext.Current.Session[sesskey].ToString());
            Response.Write("<br/>");
        }        
    }

This way, you continue to access the Session object only through the proxy class (thus maintaining encapsulation) and also giving you the option to remove a particular session variable in a "strongly-typed" way (i.e. without having to resort to string literals).

Of course, one downside to this is that all of your session variables must be "pre-defined" within your enumeration, but that was pretty much the case if you're using private string constants, too.

There's probably another way of doing this involving defining an interface (say, ISessionVariable<T> allowing the interface to be both generic (for the strongly-typed datatype) as well as "exposing" a variable name) and having a number of classes implement this interface. The Session Proxy class could then be refactored to allow "injection" of any class implementing the ISessionVariable<T> interface, and allowing get and set type operation on that ISessionVariable implementing class in a strongly-typed way. This allows the Session Proxy class itself to be completely agnostic of the different session variables you'll be using, however, this approach does still require that all of the classes (one for each session variable you're going to use) be pre-defined in advance somewhere within your application to ultimately be "injected" into the Session Proxy class. Since we're only talking about "wrapping" the session object and some variables (the list of which is probably fairly fixed and not too large), I think the interface/injection route is overkill (although arguably better designed and certainly more DRY), and personally, I'd go with the enum option.

CraigTP
CraigTP, Thank you very much for your solution and examples!! It looks perfect for me. I will use 1st method (enums) for my current project. Thank you for your design advices, I will add to my SessionProxy class SessionProxy.Remove, Clear, Abandon and other which I will use. Greetings!
binball