【问题标题】:Issue with a manually instantiated SessionState provider手动实例化 SessionState 提供程序的问题
【发布时间】:2013-03-27 02:15:18
【问题描述】:

我正在开发一个原型程序,它应该测试 ASP.NET 的不同(SessionState、Profile 等)提供程序,即 MySQL、Oracle 等。目前我正在使用 MySQL 提供程序。我刚刚成功地实例化了提供者、SessionStateContainer 和 SessionState 本身。

Type mySqlType = Type.GetType("MySql.Web.SessionState.MySqlSessionStateStore, MySql.Web, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d", true, true);

SessionStateStoreProviderBase provider = (SessionStateStoreProviderBase)Activator.CreateInstance(mySqlType);
System.Collections.Specialized.NameValueCollection providerConfig = new System.Collections.Specialized.NameValueCollection();
providerConfig.Add("connectionStringName", "LocalMySqlServer");
providerConfig.Add("applicationName", "/");
providerConfig.Add("autogenerateschema", "True");
providerConfig.Add("enableExpireCallback", "False");

provider.Initialize("MySqlSessionStateProvider", providerConfig);

HttpContext context = new HttpContext(
                          new HttpRequest("fake", "http://localhost:14359", ""),
                          new HttpResponse(new StringWriter()));

SessionStateStoreData storeData = provider.CreateNewStoreData(context, 100);
System.Web.SessionState.HttpSessionStateContainer sessionStateContainer =
    new System.Web.SessionState.HttpSessionStateContainer(
            "mySession",
            storeData.Items,
            storeData.StaticObjects,
            100,
            true,
            System.Web.HttpCookieMode.UseDeviceProfile,
            SessionStateMode.Custom,
            false
    );

Type sessionStateType = Type.GetType("System.Web.SessionState.HttpSessionState, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
HttpSessionState sessionState =
    (HttpSessionState)sessionStateType
        .GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(IHttpSessionState) }, null)
        .Invoke(new object[] { ssessionStateContainer });

provider.InitializeRequest(context);

一切似乎都运行良好,因为我可以在我创建的会话中写入一些值,并且可以从那里读取它们:

sessionStateContainer.Add("SomeKey", "SomeValue");
var test = sessionStateContainer["SomeKey"];
Console.WriteLine("var test: " + test.ToString()); // outputs "var test: SomeValue"

sessionState.Add("AnotherKey", "SomeOtherValue");
var test2 = sessionState["AnotherKey"];
Console.WriteLine("var test2: " + test2.ToString()); // outputs "var test2: SomeOtherValue"

// End the request
provider.EndRequest(context);

有趣的部分来了——当我检查数据库中的my_aspnet_sessions 表时,里面什么都没有。

所以我想知道数据是在哪里写入的还是我做错了什么?

更新:
即使这个问题不再是一个障碍,我仍然很想知道,如果有人愿意尝试一下,这是我用过的connectionString

<connectionStrings>
  <remove name="LocalMySqlServer" />
  <add name="LocalMySqlServer" connectionString="server=localhost;database=session_test;User Id=user;password=pass" providerName="MySql.Data.MySqlClient" />
</connectionStrings>

您还需要MySQL Connector NET

【问题讨论】:

  • 您可以通过创建新的.Invoke(new object[] { ssessionStateContainer }); 来清除这一行中的数据吗?当您单步执行代码时,您会看到任何数据吗?
  • 两个sn-ps在我的代码中的顺序相同。 sessionState实例化后的数据写入结果,看不出来怎么清除?单步执行代码时,我可以在相应的属性中看到键 SomeKeyAnotherKey,但不仅如此 - 不是。

标签: c# mysql session-state


【解决方案1】:

您在数据库中看不到任何数据,因为SessionStateModule 等待请求端调用命令SetAndReleaseItemExclusive。数据一直保存在内存中,直到调用了这样的命令。事实上,文档指出:

SessionStateModule 对象在请求结束时调用 SetAndReleaseItemExclusive 方法,在 ReleaseRequestState 事件期间,将当前会话项信息插入数据存储或使用当前值更新数据存储中的现有会话项信息,以更新项目的过期时间,并释放对数据的锁定。仅更新与提供的会话 id 和 lockId 值匹配的当前应用程序的会话数据。有关锁定的更多信息,请参阅 SessionStateStoreProviderBase 类概述中的“锁定会话存储数据”。

要进一步了解详情,您可以查看relevant files from the mono codebase

鉴于此,要查看数据库中的会话数据,您应该执行以下操作:

object storeLockId = new object();
sessionStateContainer.Add("SomeKey", "SomeValue");
var test = sessionStateContainer["SomeKey"];
Console.WriteLine("var test: " + test.ToString());

sessionState.Add("AnotherKey", "SomeOtherValue");
var test2 = sessionState["AnotherKey"];
Console.WriteLine("var test2: " + test2.ToString()); 

// End the request
provider.SetAndReleaseItemExclusive (context, sessionStateContainer.SessionID, 
                                     storeData, storeLockId, true);
provider.EndRequest(context);

【讨论】:

  • 我确实调用了提供者的EndRequest() 方法。刚刚更新了我问题中的代码 sn-p。
  • @Havelock 如您所见here stateprovider 的 EndRequest 通常为空。 SessionStateModuleOnRequestEnd 处理程序 中调用 SetAndReleaseItemExclusive(通过 OnReleaseRequestState)。
  • 请注意,显然 MS.NET 实现可能不同,但 Mono 的行为符合文档(以尽量减少移植问题)。
  • 反对票不是来自我,但我很乐意支持它,在我看来,它是朝着正确的方向。不幸的是,我没有太多时间来摆弄代码。
  • 添加了一个代码示例(注意代码中缺少的锁对象)。在 SetAndReleaseItemExclusive 调用之后,您应该在数据库中找到会话项目。
【解决方案2】:

在你的 web.config 中,你需要设置 mode="custom"

 <sessionState mode="Custom" customProvider="YourProvider">

否则,无论提供者如何,会话数据都将存储在内存中。

【讨论】:

  • Custom 模式是在实例化 HttpSessionStateContainer sessionStateContainer 时指定的(参见上面的代码)。调试时检查字段,发现模式确实是Custom,所以这不是问题。
  • @Havelock - 尝试打开 mysql 日志记录。看看是否有任何东西被发送到mysql。也许它被发送到数据库,但没有提交。
  • 好主意,但不幸的是没有帮助。
  • 是否有任何查询被发送到数据库?
  • 是的,但与会话数据无关。最接近的一个是SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='my_aspnet_sessions'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-17
  • 2018-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多