is it a good idea to create an enum for the key names of session values?

后端 未结 7 2203
失恋的感觉
失恋的感觉 2021-02-14 22:45

instead of doing

 session(\"myvar1\") = something
 session(\"myvar2\") = something
 session(\"myvar3\") = something
 session(\"myvar4\") = something
相关标签:
7条回答
  • 2021-02-14 22:55

    I came up with a solution that avoids certain disadvantages of the other solutions posted by keeping the structure of the Session variables intact. It is simply a type-safe shortcut to get and set Session variables.

    It's C#, but I posted some auto-generated VB.NET at the end.

    The best solutions I have seen (the accepted answer and the one by TheObjectGuy) require a custom class that is stored in a Session variable, and then is pulled from the Session to access its properties with something like MySessionClass.Current.MyProperty.

    The problem with this is that if you are currently using (or may use in the future) something other than an InProc Session-State mode (see https://msdn.microsoft.com/en-us/library/ms178586%28v=vs.140%29.aspx), the whole class would have to go through serialization to access a single property.

    Also, that means you lose the IEnumerable and ICollection implementations offered by the actual Session, if you need those. With my solution, you can simply access the actual Session if you need this functionality.

    You can easily use these session variables and they are type-safe. It can be used alongside statements like Session["MyProperty"], which will allow for conversion of an existing project one reference at a time. So:

    int myInt = (int)Session["MyInt"];
    Session["MyInt"] = 3;
    

    becomes:

    int myInt = SessionVars.MyInt; 
    SessionVars.MyInt = 3;
    

    Here is the actual class. The CallerMemberName requires .NET 4.5, but even if you are using an older version you could still manage it by explicitly passing the propertyName. Also, the types of the properties must be nullable to make it act exactly the same as standard Session["MyProp"] calls because a non-set

    public static class SessionVars
    {
        private static T Get2<T>([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") 
        {
            if (HttpContext.Current.Session[propertyName] == null)
            {
                return default(T);
            }
    
            return (T)HttpContext.Current.Session[propertyName];
        }
    
        private static void Set2<T>(T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
        {
            HttpContext.Current.Session[propertyName] = value;
        }
    
        public static int MyInt { get { return Get2<int>(); } set { Set2<int>(value); } }
        public static bool MyBool { get { return Get2<bool>(); } set { Set2<bool>(value); } }
        public static string MyString { get { return Get2<string>(); } set { Set2<string>(value); } }
    }
    

    I even wrote a code snippet to facilitate adding these properties:

    <?xml version="1.0" encoding="utf-8"?>
    <CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <Header>
        <Title>SessionVars Property</Title>
        <Author>kevinpo</Author>
        <Shortcut>sv</Shortcut>
        <Description>Adds a property for use in a SessionVars class</Description>
        <SnippetTypes>
          <SnippetType>Expansion</SnippetType>
        </SnippetTypes>
      </Header>
      <Snippet>
        <Declarations>
          <Literal>
            <ID>type</ID>
            <Default>int</Default>
          </Literal>
          <Literal>
            <ID>property</ID>
            <Default>PropertyName</Default>
          </Literal>
        </Declarations>
        <Code Language="CSharp">
          <![CDATA[public static $type$ $property$ { get { return Get2<$type$>(); } set { Set2<$type$>(value); } }]]>
        </Code>
      </Snippet>
    </CodeSnippet>
    

    I'm a C# guy, so this VB.NET is just auto-converted by http://converter.telerik.com/:

    Public NotInheritable Class SessionVars
        Private Sub New()
        End Sub
        Private Shared Function Get2(Of T)(<System.Runtime.CompilerServices.CallerMemberName> Optional propertyName As String = "") As T
            If HttpContext.Current.Session(propertyName) Is Nothing Then
                Return Nothing
            End If
            Return DirectCast(HttpContext.Current.Session(propertyName), T)
        End Function
    
        Private Shared Sub Set2(Of T)(value As T, <System.Runtime.CompilerServices.CallerMemberName> Optional propertyName As String = "")
            HttpContext.Current.Session(propertyName) = value
        End Sub
    
        Public Shared Property MyInt() As Integer
            Get
                Return Get2(Of Integer)()
            End Get
            Set
                Set2(Of Integer)(value)
            End Set
        End Property
        Public Shared Property MyBool() As Boolean
            Get
                Return Get2(Of Boolean)()
            End Get
            Set
                Set2(Of Boolean)(value)
            End Set
        End Property
        Public Shared Property MyString() As String
            Get
                Return Get2(Of String)()
            End Get
            Set
                Set2(Of String)(value)
            End Set
        End Property
    End Class
    
    '=======================================================
    'Service provided by Telerik (www.telerik.com)
    'Conversion powered by NRefactory.
    'Twitter: @telerik
    'Facebook: facebook.com/telerik
    '=======================================================
    
    0 讨论(0)
  • 2021-02-14 23:02

    How about:-

    public static class  SessionVar
    {
      public static readonly string myVar1 = "myVar1";
      public static readonly string myVar2 = "myVar2";
      public static readonly string myVar3 = "myVar3";
      public static readonly string myVar4 = "myVar4";
    }
    

    This allows you to use:-

    session(SessionVar.myVar1) = something;
    
    0 讨论(0)
  • 2021-02-14 23:03

    I've used classes like this to make a typed session/cache wrapper. You may need to add additional code to the get/set, but I'll leave that up to you.

    internal class SessionHelper
    {
        private const string  myVar1Key = "myvar1";
    
        public static int MyVar1
        {
            get
            {
                return (int)System.Web.HttpContext.Current.Session[myVar1Key];
            }
            set
            {
                System.Web.HttpContext.Current.Session[myVar1Key] = value;
            }
        }
    }
    

    Sorry about the C#....

    0 讨论(0)
  • 2021-02-14 23:04

    Instead of using constants for the session keys, I'm using my own type-safe session object, which looks like this (sorry this is in C#, see below for a VB version):

    public class MySession
    {
      // Private constructor (use MySession.Current to access the current instance).
      private MySession() {}
    
      // Gets the current session.
      public static MySession Current
      {
        get
        {
          MySession session = HttpContext.Current.Session["__MySession__"] as MySession;
          if (session == null)
          {
            session = new MySession();
            HttpContext.Current.Session["__MySession__"] = session;
          }
          return session;
        }
      }
    
      // My session data goes here:
      public string MyString { get; set; };
      public bool MyFlag { get; set; };
      public int MyNumber { get; set; };
    }
    

    Whenever I need to read/write something to/from the session, I can use my typesafe session object like this:

    string s = MySession.Current.MyString;
    s = "new value";
    MySession.Current.MyString = s;
    

    This solution results in several advantages:

    • I have a typesafe Session (no more type-casts)
    • I can document all session based data (by commenting the public properties in MySession)
    • When adding a new element to the session, I don't have to search the solution to check if the same session-key was already used somewhere else.

    Update: Here's a VB version (automatically converted from the C# version). Sorry, but I don't know VB and so I didn't know how to write the properties in VB:

    Public Class MySession
        ' Private constructor (use MySession.Current to access the current instance).
        Private Sub New()
        End Sub
    
        ' Gets the current session.
        Public Shared ReadOnly Property Current() As MySession
            Get
                Dim session As MySession = TryCast(HttpContext.Current.Session("__MySession__"), MySession)
                If session = Nothing Then
                    session = New MySession()
                    HttpContext.Current.Session("__MySession__") = session
                End If
                Return session
            End Get
        End Property
    
        ' My session data goes here:
        Public MyString As String
        Public MyFlag As Boolean
        Public MyNumber As Integer
    End Class
    
    0 讨论(0)
  • 2021-02-14 23:06

    Only if those values are related. Otherwise use plain old constants.

    0 讨论(0)
  • 2021-02-14 23:06

    I realize this question was asked a while ago and an "answer" has already been picked. But I just came across it. Martin's answer is good. However, to assist anyone who stumbles across this in the future, if you really want a slick way to deal with Session, read this post. I don't think you'll find anything easier.

    0 讨论(0)
提交回复
热议问题