1

我正在迁移一个当前使用内存会话存储的应用程序,作为迁移的一部分,它的支持数据库正在升级到 SQL Server 2017,因此我热衷于用微软的新 SQL Server 异步替换进程内会话状态内存表支持(asp.net session state with sql-server in memory oltp)。但是,由于我实际上是从一个新数据库开始,文档中似乎缺少一两个步骤,而我看到的所有其他关于它的文章基本上都是 Microsoft 文章的复制/粘贴。

所以我的问题是:从没有用户数据库的空数据库服务器开始,如何正确设置 SQL Server 2017 以使用内存表进行会话状态?我尝试运行以下脚本来初始化数据库,然后运行应用程序而不对数据库进行任何进一步的更改:

USE [master]
GO

DECLARE @SQLDataFolder nvarchar(max) = cast(SERVERPROPERTY('InstanceDefaultDataPath') as nvarchar(max))
DECLARE @SQLLogFolder nvarchar(max) = cast(SERVERPROPERTY('InstanceDefaultLogPath') as nvarchar(max))
DECLARE @SQL nvarchar(max) = N'';

SET @SQL = N'
CREATE DATABASE [MySessionDb]
 CONTAINMENT = NONE
 ON  PRIMARY 
    (NAME = N''MySessionDb'', FILENAME = N''' + @SQLDataFolder + 'MySessionDb.mdf'' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB ), 
 FILEGROUP [MySessionDb_mod] CONTAINS MEMORY_OPTIMIZED_DATA  DEFAULT
    (NAME = N''MySessionDb_mod'', FILENAME = N''' + @SQLLogFolder + 'MySessionDb_mod'' , MAXSIZE = UNLIMITED)
 LOG ON 
    (NAME = N''MySessionDb_log'', FILENAME = N''' + @SQLLogFolder + 'MySessionDb_log.ldf'' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB );

ALTER DATABASE [MySessionDb] SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT=ON;'

EXECUTE (@SQL)
GO

当我运行应用程序时,它似乎启动正常,并且我可以看到表dbo.ASPStateTempSessions已创建。然而,浏览第一页之后,我很快发现自己陷入了错误的海洋:

System.Data.SqlClient.SqlException (0x80131904): The current transaction attempted to update a record that has been updated since this transaction started. The transaction was aborted.
Uncommittable transaction is detected at the end of the batch. The transaction is rolled back.
The statement has been terminated.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader(Boolean isInternal, Boolean forDescribeParameterEncryption)
   at System.Data.SqlClient.SqlCommand.InternalEndExecuteReader(IAsyncResult asyncResult, String endMethod, Boolean isInternal)
   at System.Data.SqlClient.SqlCommand.EndExecuteReaderInternal(IAsyncResult asyncResult)
   at System.Data.SqlClient.SqlCommand.EndExecuteReaderAsync(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNet.SessionState.SqlSessionStateRepositoryUtil.<SqlExecuteReaderWithRetryAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNet.SessionState.SqlInMemoryTableSessionStateRepository.<GetSessionStateItemAsync>d__19.MoveNext()

知道我做错了什么吗?

更新

我的配置web.config\system.web如下所示:

<sessionState cookieless="false" regenerateExpiredSessionId="true" mode="Custom" customProvider="SqlSessionStateProviderAsync">
    <providers>
        <add name="SqlSessionStateProviderAsync" 
             connectionStringName="MySessionStateConnectionString"
             type="Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync, Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
             UseInMemoryTable="true"
             MaxRetryNumber="5"
             RetryInterval="100" />
    </providers>
</sessionState>

还有用于添加会话状态 HTTP 模块的默认配置(用于异步会话支持,IIRC)。

4

0 回答 0