squirrel_sc

主要研究.net和asp,欢迎讨论、指正。
分享技术,分享快乐。
posts - 25, comments - 561, trackbacks - 3, articles - 1

遍历所有session并取值

Posted on 2004-12-28 11:45 squirrel_sc 阅读(3739) 评论(5) 编辑 收藏
    首先要说明的是,该方法仅对将session存放于sql server中有效。很多人说session存放于sql server中效率太低,我觉得这只能说低一些,不能说太低。这其中的好处更大一些,如果将session存放在进程内,应用程序一重启就没了,有时候很麻烦;存放在进程外和存放在数据库中效率几乎一样。

这个类是从.net framework的源码里得到的,删除了updatesession的部分,只保留了获得session的部分,可以单独作为一个类或者放在类中做私有类使用。
#Region "分析Session的私有类"
    Private Class altSerialization
        
' Methods
        Shared Sub New()
            
Dim typeArray1 As Type() = New Type(21) {}
            typeArray1(
1= GetType(String)
            typeArray1(
2= GetType(Integer)
            typeArray1(
3= GetType(Boolean)
            typeArray1(
4= GetType(DateTime)
            typeArray1(
5= GetType(Decimal)
            typeArray1(
6= GetType(Byte)
            typeArray1(
7= GetType(Char)
            typeArray1(
8= GetType(Single)
            typeArray1(
9= GetType(Double)
            typeArray1(
10= GetType(SByte)
            typeArray1(
11= GetType(Short)
            typeArray1(
12= GetType(Long)
            typeArray1(
13= GetType(UInt16)
            typeArray1(
14= GetType(UInt32)
            typeArray1(
15= GetType(UInt64)
            typeArray1(
16= GetType(TimeSpan)
            typeArray1(
17= GetType(Guid)
            typeArray1(
18= GetType(IntPtr)
            typeArray1(
19= GetType(UIntPtr)
            altSerialization.s_serializedTypes 
= typeArray1
        
End Sub


        
Private Sub New()
        
End Sub


        
Public Shared Function ReadValueFromStream(ByVal reader As BinaryReader) As Object
            
Dim numArray1 As Integer()
            
Dim num1 As Integer
            
Dim buffer1 As Byte()
            
Dim formatter1 As System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            
Dim obj1 As Object = Nothing
            
Select Case CType(reader.ReadByte, TypeID)
                
Case CType(CType(CType(1, TypeID), TypeID), TypeID)
                    
Return reader.ReadString
                
Case CType(CType(CType(2, TypeID), TypeID), TypeID)
                    
Return reader.ReadInt32
                
Case CType(CType(CType(3, TypeID), TypeID), TypeID)
                    
Return reader.ReadBoolean
                
Case CType(CType(CType(4, TypeID), TypeID), TypeID)
                    
Return New DateTime(reader.ReadInt64)
                
Case CType(CType(CType(5, TypeID), TypeID), TypeID)
                    numArray1 
= New Integer(4) {}
                    num1 
= 0
                    
GoTo Label_00CA
                
Case CType(CType(CType(6, TypeID), TypeID), TypeID)
                    
Return reader.ReadByte
                
Case CType(CType(CType(7, TypeID), TypeID), TypeID)
                    
Return reader.ReadChar
                
Case CType(CType(CType(8, TypeID), TypeID), TypeID)
                    
Return reader.ReadSingle
                
Case CType(CType(CType(9, TypeID), TypeID), TypeID)
                    
Return reader.ReadDouble
                
Case CType(CType(CType(10, TypeID), TypeID), TypeID)
                    
Return reader.ReadSByte
                
Case CType(CType(CType(11, TypeID), TypeID), TypeID)
                    
Return reader.ReadInt16
                
Case CType(CType(CType(12, TypeID), TypeID), TypeID)
                    
Return reader.ReadInt64
                
Case CType(CType(CType(13, TypeID), TypeID), TypeID)
                    
Return reader.ReadUInt16
                
Case CType(CType(CType(14, TypeID), TypeID), TypeID)
                    
Return reader.ReadUInt32
                
Case CType(CType(CType(15, TypeID), TypeID), TypeID)
                    
Return reader.ReadUInt64
                
Case CType(CType(CType(16, TypeID), TypeID), TypeID)
                    
Return New TimeSpan(reader.ReadInt64)
                
Case CType(CType(CType(17, TypeID), TypeID), TypeID)
                    buffer1 
= reader.ReadBytes(16)
                    
Return New Guid(buffer1)
                
Case CType(CType(CType(18, TypeID), TypeID), TypeID)
                    
If (IntPtr.Size = 4Then
                        
Return New IntPtr(reader.ReadInt32)
                    
End If
                    
GoTo Label_01D3
                
Case CType(CType(CType(19, TypeID), TypeID), TypeID)
                    
If (UIntPtr.Size = 4Then
                        
Return New UIntPtr(reader.ReadUInt32)
                    
End If
                    
GoTo Label_0201
                
Case CType(CType(CType(20, TypeID), TypeID), TypeID)
                    formatter1 
= New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
                    
Return formatter1.Deserialize(reader.BaseStream)
                
Case CType(CType(CType(21, TypeID), TypeID), TypeID)
                    
GoTo Label_022B
            
End Select
            
Return obj1
Label_00BD:
            numArray1(num1) 
= reader.ReadInt32
            num1 
= (num1 + 1)
Label_00CA:
            
If (num1 < 4Then
                
GoTo Label_00BD
            
End If
            
Return New Decimal(numArray1)
Label_01D3:
            
Return New IntPtr(reader.ReadInt64)
Label_0201:
            
Return New UIntPtr(reader.ReadUInt64)
Label_022B:
            
Return Nothing
        
End Function


        
' Fields
        Private Shared s_serializedTypes As Type()

        
' Nested Types
        Private Enum TypeID
            
' Fields
            [Boolean= 3
            [
Byte= 6
            [
Char= 7
            DateTime 
= 4
            [
Decimal= 5
            [
Double= 9
            Guid 
= 17
            Int16 
= 11
            Int32 
= 2
            Int64 
= 12
            IntPtr 
= 18
            [Null] 
= 21
            [
Object= 20
            SByte 
= 10
            [
Single= 8
            [
String= 1
            TimeSpan 
= 16
            UInt16 
= 13
            UInt32 
= 14
            UInt64 
= 15
            UIntPtr 
= 19
        
End Enum

    
End Class

#
End Region


使用它的核心代码(.net framework对我抛弃的几个bool以及数值进行了一些判断,我没有深究,有朋友研究过的请指点一下。)
Dim sql As String = "select * from ASPState..ASPStateTempSessions where datediff(minute, LockDateLocal, GetDate()) < 20"
Dim dt As New DataTable
DataDriver.GetRows(sql, dt) 
'该方法用于从数据库中获取一个数据集,可参考我的文章:http://www.cnblogs.com/squirrel_sc/archive/2004/11/04/60447.html
Dim sTemp As String
Dim obj As Object
Dim st As New MemoryStream
Dim str As New BinaryReader(st)
Dim col As New System.Collections.Specialized.NameValueCollection
For i As Integer = 0 To dt.Rows.Count - 1
  
Dim bTemp() As Byte = dt.Rows(i)("SessionItemShort")
  st.SetLength(
0)
  st.
Write(bTemp, 0, bTemp.Length)
  st.
Seek(0, SeekOrigin.Begin)
  
str.ReadInt32()
  
str.ReadBoolean()
  
str.ReadBoolean()
  
str.ReadBoolean()
  
Dim iCount As Integer = str.ReadInt32
  
Dim btTemp As Byte
  
str.ReadInt32()
  
For k As Integer = 0 To iCount - 1
    sTemp 
= str.ReadString
    obj 
= altSerialization.ReadValueFromStream(str)
    
'obj就是sTemp这个session名字对应的内容,它的类型不定。在这里对其进行操作就可以了
  Next
Next
str.Close()
st.Close()


使用实例:
该方法用于遍历所有session,形成在线用户列表。由于这个操作可能效率较低,所以把结果在内存中缓存1分钟。用户名存在名为UserName的session中。
    Private Shared _onlineUserList As ArrayList
    
Private Shared _onlineUserUpdateTime As DateTime

    
Public Shared Function GetOnlineUserList() As ArrayList
        
If (_onlineUserList Is NothingThen
            _onlineUserList 
= New ArrayList
            _onlineUserUpdateTime 
= Now
        
End If
        
If (_onlineUserUpdateTime.AddMinutes(1< Now OrElse _onlineUserList.Count = 0Then
            _onlineUserList.Clear()
            
Dim sql As String = "select * from ASPState..ASPStateTempSessions where datediff(minute, LockDateLocal, GetDate()) < 20"
            Dim dt As New DataTable
            DataDriver.GetRows(sql, dt)
            
Dim sTemp As String
            
Dim obj As Object
            
Dim st As New MemoryStream
            
Dim str As New BinaryReader(st)
            
Dim col As New System.Collections.Specialized.NameValueCollection
            
For i As Integer = 0 To dt.Rows.Count - 1
                
Dim bTemp() As Byte = dt.Rows(i)("SessionItemShort")
                st.SetLength(
0)
                st.
Write(bTemp, 0, bTemp.Length)
                st.
Seek(0, SeekOrigin.Begin)
                
str.ReadInt32()
                
str.ReadBoolean()
                
str.ReadBoolean()
                
str.ReadBoolean()
                
Dim iCount As Integer = str.ReadInt32
                
Dim btTemp As Byte
                
str.ReadInt32()
                
For k As Integer = 0 To iCount - 1
                    sTemp 
= str.ReadString
                    obj 
= altSerialization.ReadValueFromStream(str)
                    
If (sTemp = "UserName" AndAlso _onlineUserList.BinarySearch(obj) < 0Then
                        _onlineUserList.Add(
DirectCast(obj, String))
                        
Exit For
                    
End If
                
Next
            
Next
            
str.Close()
            st.Close()
            _onlineUserUpdateTime 
= Now
        
End If
        
Return _onlineUserList
    
End Function

关于设置:
我使用的是信任连接,在XP下就是aspnet用户,ASPState数据库就是它的,所以访问数据库的权限上没有问题。session存放在sql server中要使用持久的那种,如果是存放在tempDb中的,一重启机器后,权限就要重新设置,很苦恼。

Feedback

#1楼  回复 引用 查看   

2004-12-28 13:55 by onekey      
我的Session保存的是对象:

Customer customer = new Customer();
customer.name = name;

Session["Customer"] = customer;

可不可以也用sql server存放?

#2楼[楼主]  回复 引用 查看   

2004-12-28 14:19 by squirrel_sc      
可以试试。可能需要你的对象支持序列化。

另外,大对象不一定会存放在SessionItemShort这个字段里,后面还有一个binary的SessionItemLong,可能会存放在这里面,不过这样的话,效率可能会很低了。

#3楼  回复 引用   

2006-05-05 09:25 by angelo[未注册用户]
Do you have a sample of page using the session data?

#4楼[楼主]  回复 引用 查看   

2006-05-08 17:27 by squirrel_sc      
直接调用GetOnlineUserList就可以了
 
在.net 2.0里面,有了一个新的类System.Web.SessionState.SessionStateItemCollection,这样操作起来就简单多了。
 
 
Public Shared Function GetOnlineUserList() As ArrayList
            
SyncLock _onlineUserList
                
If (CacheManager.CanUpdate("OnlineUserList"OrElse _onlineUserList.Count = 0Then
                    _onlineUserList.Clear()
                    
Dim sql As String = "select * from ASPState..ASPStateTempSessions(NOLOCK) where datediff(minute, LockDateLocal, GetDate()) < 20 order by Created Desc"
                    
Dim dt As New DataTable
                    DataDriver.GetRows(sql, dt)
                    
Dim st As New MemoryStream
                    
Dim str As New BinaryReader(st)
                    
Dim ssc As System.Web.SessionState.SessionStateItemCollection
                    
Dim b1 As Boolean

                    _onlineCount 
= dt.Rows.Count
                    
For i As Integer = 0 To dt.Rows.Count - 1
                        
Try
                            
Dim bTemp() As Byte = dt.Rows(i)("SessionItemShort")
                            st.SetLength(
0)
                            st.Write(bTemp, 
0, bTemp.Length)
                            st.Seek(
0, SeekOrigin.Begin)
                            
str.ReadInt32()
                            b1 
= str.ReadBoolean()
                            
str.ReadBoolean()

                            
If (b1) Then
                                ssc 
= System.Web.SessionState.SessionStateItemCollection.Deserialize(str)
                                
If ((Not ssc("UserName"Is NothingAndAlso _
                                    ssc(
"UserName").ToString().Length > 0 AndAlso _
                                    _onlineUserList.BinarySearch(ssc(
"UserName")) < 0Then
                                    _onlineUserList.Add(ssc(
"UserName"))
                                
End If
                            
End If
                        
Catch ex As Exception
                            
Dim value As String
                            
Dim btInput() As Byte
                            
Dim stEx As New MemoryStream()
                            
Dim swEx As New StreamWriter(stEx)
                            
Dim srEx As New StreamReader(stEx)

                            
If (Not dt.Rows(i)("SessionItemShort"Is DBNull.Value) Then
                                btInput 
= CType(dt.Rows(i)("SessionItemShort"), Byte())
                                
For j As Integer = 0 To btInput.Length - 1
                                    swEx.Write(
"{0:X2}", btInput(j))
                                
Next
                                swEx.Flush()
                                stEx.Seek(
0, SeekOrigin.Begin)
                                value 
= srEx.ReadToEnd()
                                UtilTools.SaveDebugInfo(
"这个session有问题:" & value & vbCrLf & ex.ToString(), True)
                            
End If
                        
End Try
                    
Next
                    
str.Close()
                    st.Close()
                
End If
            
End SyncLock
            
Return _onlineUserList
        
End Function

#5楼  回复 引用   

2008-06-24 11:08 by 士大夫[未注册用户]
CacheManager.CanUpdate("OnlineUserList") 看不懂是什么意思