rouen
rouen

Reputation: 5124

Variable wrapper for session-persistance

i am pretty sure i saw nice thing some time ago (maybe in Enterprise library, not sure), but i just cant google it now - generic variable wrapper for making it persistent by storing it in session. Usage like this:

Persistent< string > Name {get;set;}

// reguest 1.

Name = "A"; // in fact storing to session.. maybe Name.Value = "A" is necessary, not sure if implicit cast can be done here

// reguest 2.

return Name; // returns string "A", implicit conversion

of course, I would implement it myself already before asking, but i cant think of any good (consistent and fast) way to determine session keys for variables (how to make sure, I will get the same for the Name every time, but different for Age, you know..)

Thanx, Roman

Upvotes: 1

Views: 978

Answers (4)

AechoLiu
AechoLiu

Reputation: 18378

Thanks jim31415 and I wrapper my session like followings,

internal class SessionHelper {
    private void Set<T>(string key, T value) {
        HttpContext.Current.Session[key] = value;
    }
    private T Get<T>(string key) {
        return (T)HttpContext.Current.Session[key];
    }

    public int MemberID {
        get { return Get<int>("SK_MemberID"); }
        set { Set<int>("SK_MemberID", value); }
    }
    public string MemberAccount {
        get { return Get<string>("SK_MemberAccount"); }
        set { Set<string>("SK_MemberAccount", value); }
    }
    public string MemberDisplayName {
        get { return Get<string>("SK_MemberDisplayName"); }
        set { Set<string>("SK_MemberDisplayName", value); }
    }
    public string MemberGuid {
        get { return Get<string>("SK_MemberGuid"); }
        set { Set<string>("SK_MemberGuid", value); }
    }
}

With this thread, the helper class can be declared with static keyword.

Upvotes: 0

jim31415
jim31415

Reputation: 8808

Something along these lines:

private int CustomerID
{
    get
    {
        if( Session["CustomerID"] != null )
            return Convert.ToInt32( Session["CustomerID"] );
        else
            return 0;
    }
    set { Session["CustomerID"] = value; }
}

EDIT:

An alternative might be something like this:

public class Persist<T>
{
    private string ObjectName;

    public Persist( string Name )
    {
        ObjectName = Name;
    }

    public T Get()
    {
        return (T)(HttpContext.Current.Session[ObjectName]); 
    }

    public void Set(T value)
    {
        HttpContext.Current.Session[ObjectName] = value;
    }
}

This is shown wrapped into a simple Singleton class.

public class SV
{
    private static readonly SV instance = new SV( );

    public Persist<DateTime> FiscalDate;
    public Persist<decimal> Revenue;

    private SV( )
    {
        FiscalDate = new Persist<DateTime>( "FiscalDate" );
        Revenue = new Persist<decimal>( "Revenue" );
    }

   public static SV Instance
   {
      get 
      {
         return instance; 
      }
   }
}

Usage is a bit wordy, unfortunately.

protected void Page_Load( object sender, EventArgs e )
{
    if( !Page.IsPostBack )
    {
        SV.Instance.Revenue.Set( 1234567890M );
        SV.Instance.FiscalDate.Set( new DateTime( 2011, 3, 15 ) );
    }
}

protected void Button1_Click( object sender, EventArgs e )
{
    DateTime when = SV.Instance.FiscalDate.Get( );
    decimal amount = SV.Instance.Revenue.Get( );
}

Upvotes: 1

Matthew Abbott
Matthew Abbott

Reputation: 61589

I guess one way you could do it is:

public class Persistent<T>
{
    private readonly string _sessionKey;
    private static readonly bool _valueType;

    static Persistent()
    {
        _valueType = typeof(T).IsValueType;
    }

    public Persistent(T value = default(T))
    {
        _sessionKey = Guid.NewGuid().ToString();
        SetValue(value);
    }

    private void SetValue(T value)
    {
        var item = (_valueType)
          ? new PersistentWrapper { Value = value }
          : (object)value;

        HttpContext.Current.Session[_sessionKey] = item;
    }

    private T GetValue()
    {
        object item = HttpContext.Current.Session[_sessionKey];
        if (item != null)
        {
            if (_valueType) return ((PersistentWrapper)item).Value;

            return (T)item;
        }

        return default(T);
    }

    [Serializable]
    private class PersistentWrapper
    {
        public T Value { get; set; }
    }

    public static implicit operator T(Persistent<T> value)
    {
        if (value == null) return default(T);
        return value.GetValue();
    }

    public static implicit operator Persistent<T>(T value)
    {
        return new Persistent<T>(value);
    }
}

Which could be used as:

public class Person
{
    public Persistent<string> Name { get; set; }
    public Persistent<int> Age { get; set; }
}

With usage:

var person = new Person();
person.Name = "Matt";
person.Age = 27;

Although it just feels dirty to me...

Upvotes: -1

Tejs
Tejs

Reputation: 41236

If you're going to make a custom session wrapper, I would suggest using an expression to make sure your magic strings don't get outdated.

 public int SomeProperty
 {
     get { return GetValueFor(x => x.SomeProperty); }
     set { SetValueFor(x => x.SomeProperty, value); }
 }

 protected T GetValueFor<T>(Expression<Func<ThisClass, T>> propertySelector)
 {
     string propertyName = // Get Value from expression.. to loo long to post here

     return (T)_session[propertyName];
 }

 protected SetValueFor<T>(Expression<Func<ThisClass, T>> propertySelector, object value)
 {
     string propertyName = // Get value from expression

     _session[propertyName] = value;
 }

This way, all your properties are just mapped on the session object in a strongly typed way, and if you ever refactor, you dont have to worry about magic strings.

Upvotes: 2

Related Questions