我正在使用SQL Server 2008为.NET4应用程序存储会话。会话将存储在[DatabaseA]中。对此没有任何其他自定义配置,因此ASPState数据库完全是开箱即用的方式(使用aspnet_regsql)

我的主应用程序在[DatabaseB](同一服务器)上运行。在此数据库中,我有2个表,这些表记录了一些数据以及sessionID。

通过SQL Agent运行[DeleteExpiredSessions]存储过程(在DatabaseA上)时,已正确地从ASPState中删除了会话,但是我想扩展它以从[DatabaseB]中删除基于SessionID的行。

我尝试编辑[DeleteExpiredSessions]存储过程以包括以下SQL

    OPEN ExpiredSessionCursor

    FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID

    WHILE @@FETCH_STATUS = 0
        BEGIN
            -- BEGIN MY ADDITIONS
            DECLARE @myRecordCount int
            SELECT @myRecordCount= COUNT(*) FROM [DatabaseB].dbo.Table1 WHERE [DatabaseB].dbo.Table1.SessionId = @SessionID -- AND [DatabaseB].dbo.Table1.DateEntered < @now
            SELECT @myRecordCount
            DELETE FROM [DatabaseB].dbo.Table1 WHERE [DatabaseB].dbo.Table1.SessionId = @SessionID AND [DatabaseB].dbo.Table1.DateEntered < @now
            DELETE FROM [DatabaseB].dbo.Table2 WHERE [DatabaseB].dbo.Table2.SessionId = @SessionID AND [DatabaseB].dbo.Table2.DateEntered < @now
            -- END MY ADDITIONS

            DELETE FROM [DatabaseA].dbo.ASPStateTempSessions WHERE SessionID = @SessionID AND Expires < @now
            FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID
        END

    CLOSE ExpiredSessionCursor

    DEALLOCATE ExpiredSessionCursor


但是@myRecordCount返回0行。
没有报告错误(代理作业正确运行,并且在SQL Profiler中没有任何错误),并且@myRecordCount在这种情况下应该返回4。

DECLARE / SELECT COUNT作为调试器存在。

更新

因此调试了sql后发现:

SELECT SessionId
        FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED)
        WHERE Expires < GETUTCDATE()
--Returns SessionId = '3wj5nyrlz02ezw1vvjts4gjv28d8c075'

SELECT * FROM [DatabaseB].dbo.Table1 -- returns (4) results
SELECT * FROM [DatabaseB].dbo.Table1 WHERE [DatabaseB].dbo.Table1.SessionId = '3wj5nyrlz02ezw1vvjts4gjv28d8c075' -- returns (0) results


我推断出SessionId是错误的。
[DatabaseB].dbo.Table1中存储的是'3wj5nyrlz02ezw1vvjts4gjv'-请注意字符串的截断。

现在,我用于存储会话变量的.NET代码(使用EF6.1.3)是
Table1.SessionId = HttpContext.Current.Session.SessionID
这表示正在存储3wj5nyrlz02ezw1vvjts4gjv
Cookie ASP.NET_SessionId也具有相同的值。

Table1的SessionId列的长度与ASPState tmpSession表的长度相同(88)

更新的问题
有趣的是,ASPStateTempSessions.SessionId变量似乎正在追加
28d8c075到它的结尾。
因此,ASP.NET_SessionId和HttpContext.Current.Session.SessionID为3wj5nyrlz02ezw1vvjts4gjv,而ASPStateTempSessions.SessionId为3wj5nyrlz02ezw1vvjts4gjv28d8c075

我刚刚清除了所有会话变量和cookie,并且有了一个新的会话变量,但是28d8c075仍被删除/附加到各种cookie和数据值中。

我知道发生这种情况是因为ASPStateTempSessions将应用程序哈希的后缀附加到SessionId(https://msdn.microsoft.com/en-us/library/aa478952.aspx

Column Name Column Type Description
SessionId   nvarchar(88)    Session ID + application ID


如何将其返回到HttpContext.Current.Session.SessionID而不是SessionId?

最佳答案

解决了

问题(正如我最初诊断的那样)是应用程序ID没有传递给SessionID变量。因此,我执行了以下步骤:

1)在Web.Config中创建了一个后备变量(AppName更改的可能性很小)

<add key="AppId" value="685293685"/>


为什么? -这是从ASPState [TempGetAppID]返回的appName的ID

2)在DatabaseB中创建一个存储过程[GetApplicationIdForSession]

DECLARE @appId int

    EXEC    [ASPState].dbo.[TempGetAppID]
        @appName = @iisName,
        @appId = @appId OUTPUT

    SELECT  @appId as N'AppId'


为什么? -这利用了将AppName哈希到正确的AppId的内置SQL State SP来保持一致性。 (即我没有编写单独的.net函数来尝试获得与SQL相同的值)

3)在Global.asax.vb中

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        Using db As New SqlConnection(ConfigurationManager.ConnectionStrings("LocalServer").ConnectionString)
            db.Open()
            Using cmd As SqlCommand = db.CreateCommand()
                cmd.CommandText = "GetApplicationIdForSession"
                cmd.CommandType = CommandType.StoredProcedure
                cmd.Parameters.AddWithValue("iisName", HttpRuntime.AppDomainAppId.ToLower)
                Using dr As SqlDataReader = cmd.ExecuteReader()
                    If dr IsNot Nothing AndAlso dr.Read() Then
                        Application("AppId") = CType(dr("appId"), Integer)
                    Else
                        Application("AppId") = CType(ConfigurationManager.AppSettings("AppId"), Integer)
                    End If
                End Using
            End Using
            db.Close()
        End Using
        ' Fires when the application is started
    End Sub


为什么? -HttpRuntime.AppDomainAppId与ASPState数据库(DatabaseA)中使用的值相同。因此我将其传递给在步骤2中创建的存储过程,然后将输出存储在应用程序变量中,这样我就不必每次都访问数据库来获取sessionid。

4)在我的页面继承自的基类中创建此函数

Public Function GetAppIdHash() As String

        Dim hashCode As Integer = CType(Application("AppId"), Integer)
        Return ((hashCode).ToString("X2")).ToLower

    End Function


为什么? -这将获取应用程序变量(“ AppId”)并返回十六进制输出

5)从以下位置更改了存储会话ID变量的.net代码:
Table1.SessionId = HttpContext.Current.Session.SessionID

Table1.SessionId = HttpContext.Current.Session.SessionID & GetAppIdHash()

6)DeleteExpiredSessions SP已更新为此处列出的-happy medium-版本-http://sqlperformance.com/2013/01/t-sql-queries/optimize-aspstate
并附加了其他SQL命令。

ALTER PROCEDURE [dbo].[DeleteExpiredSessions]
  @top INT = 1000
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @now DATETIME, @c INT;
  SELECT @now = GETUTCDATE(), @c = 1;

 /* START Additional SQL */
    CREATE TABLE #tblExpiredSessions
    (
        SessionId nvarchar(88) NOT NULL PRIMARY KEY
    )
    INSERT #tblExpiredSessions (SessionId)
        SELECT SessionId
        FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED)
        WHERE Expires < @now
    /* END Additional SQL */

  BEGIN TRANSACTION;

  WHILE @c <> 0
  BEGIN
    ;WITH x AS
    (
      SELECT TOP (@top) SessionId
        FROM [ASPState].dbo.ASPStateTempSessions
        WHERE Expires < @now
        ORDER BY SessionId
    )
    DELETE x;

    SET @c = @@ROWCOUNT;

    IF @@TRANCOUNT = 1
    BEGIN
      COMMIT TRANSACTION;
      BEGIN TRANSACTION;
    END
  END

  IF @@TRANCOUNT = 1
  BEGIN
    COMMIT TRANSACTION;
  END

  /* START Additional SQL */
  DELETE FROM DatabaseB.dbo.Table1 WHERE DatabaseB.dbo.Table2.SessionId in (SELECT * FROM #tblExpiredSessions)
  DELETE FROM DatabaseB.dbo.Table2 WHERE DatabaseB.dbo.Table2.SessionId in (SELECT * FROM #tblExpiredSessions)

  DROP TABLE #tblExpiredSessions
  /* END Additional SQL */
END


旁注-我不是SQL向导,因此如果有人可以提出对DELETE FROM DatabaseB.dbo.Table1等部分的改进建议,将不胜感激。 (例如查询中的位置,它是否可以与CTE一起使用),对我来说目前似乎有些笨拙。

关于.net - SQL session 状态-数据库SessionId与ASP.NET_SessionID值不同,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35337237/

10-11 11:48