2

我正在开发一个使用内部开发的自定义 SessionStateProvider 类的 asp.net 项目。

显然,Session_OnStart 事件没有触发。我在 Global.asax 中有代码来处理该事件。我只能通过将 Web.config 更改为使用默认的 SessionStateProvider 来执行此代码。

当我使用自定义 SessionStateProvider 类时,我必须怎么做才能执行我的 Session_OnStart 代码?我可以访问源代码。

更新:它在 MSDN 上清楚地表明,通常Session_OnStart只有在 Session 模式为 InProc 时才会触发,所以我将不得不做一些特别的事情来按照我想要的方式连接它。

我在 web.config 中的会话状态配置如下所示:

< sessionState cookieless="false" regenerateExpiredSessionId="true" mode="Custom"  
 customProvider="ProgramSessionStateProvider"  
 sessionIDManagerType="SessionIDManager.ProgramSessionIDManager"  
sqlConnectionString="SqlSessionServices" cookieName="smartSessionID" >
< providers >
            < add name="ProgramSessionStateProvider"   
type="SessionStateProvider.ProgramSessionStateProvider"   
connectionStringName="SqlSessionServices" writeExceptionsToEventLog="false" / >  
        < /providers >
    < /sessionState >

再次更新:今天早上我发现了一些有趣的东西。在阅读了 Chris 的回答后,我尝试只使用客户SessionStateProvider并删除了 custom 的代码SessionIDManager。一旦我这样做了,我立即能够看到该Session_OnStart方法执行。问题是,我的自定义SessionStateProvider 需要自定义SessionIDManager. 事件究竟是从哪里Session_OnStart触发的?看起来它与 相关SessionIDManager,而不是SessionStateProvider.

4

3 回答 3

1

编辑:看起来我确实有点错过了这个问题的重点。我将把这个答案留在这里,只是因为它可能会引起某些人的兴趣。如果您认为应该删除它,请随时发表评论。

抱歉,这是一个答案,因为我不能 100% 确定我在说什么,但评论太长了……

我不确定您是创建了自定义会话模块还是仅创建了会话状态存储提供程序。我假设该模块,但我不确定“SessionStateProvider”...

据我所知,在 web.config 中添加的任何 httpmodule 都将经历一个尝试连接到 global.asax 中的事件的过程。它这样做的方式似乎是通过寻找“{name}_{event}”或“{name}_on{event}”形式的方法并将它们连接起来,我认为{name}是你给的名字您的 web.config 和 {event} 中的模块当然是类中事件的名称(即开始)。

所以本质上,如果你的新模块是这样包含的:

<add name="MySession" type="MySessionStateModule" />

那么你会想要在你的 global.asaxMySession_Start

我希望这有帮助。对不起,如果它没有,它的所有东西你已经尝试过。我建议给出一些代码和一些关于你已经尝试过的想法,但是失败了。可能有趣的代码是您将自定义代码添加到站点的位置(即 web.config 的适当部分),如果可以轻松地将其缩减为微不足道的形式(例如,会话提供程序只是返回一个常量可能很短并显示您的错误)。还有一些迹象表明它是否保持会话状态(即它是否在不调用 onstart 的情况下工作)会很好。:)

编辑添加:我想我会链接我遇到的一个有用的网页。http://aspnetresources.com/articles/event_handlers_in_global_asax讨论了标准错误处理程序是如何在 global.asax 中连接起来的,并向我指出了有趣的方法 HookupEventHandlersForAppplicationAndModules,它给了我一些关于其中一些可能如何工作的线索。

于 2010-08-10T15:39:40.387 回答
1

处理自定义 SessionStateStores 的第二个答案。在查看代码时,我看不出它为什么不调用会话启动,所以我尝试创建自己的兼容但非功能性会话状态提供程序以查看发生了什么。使用我的会话状态提供程序,它在 global.asax 中调用 Session_start 很好。我将我的代码作为概念的演示证明:

会话状态提供者:

namespace WebApplication1
{
    public class SessionStateProvider : System.Web.SessionState.SessionStateStoreProviderBase
    {
        public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
        {
            ISessionStateItemCollection foo = new SessionStateItemCollection();
            HttpStaticObjectsCollection bar = new HttpStaticObjectsCollection();
            return new SessionStateStoreData(foo, bar, 300);
        }
        public override void CreateUninitializedItem(HttpContext context, string id, int timeout){}
        public override void Dispose() { }
        public override void EndRequest(HttpContext context) { }
        public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
        {
            locked = false;
            lockAge = TimeSpan.FromSeconds(10);
            lockId = new object();
            actions = SessionStateActions.None;
            ISessionStateItemCollection foo = new SessionStateItemCollection();
            HttpStaticObjectsCollection bar = new HttpStaticObjectsCollection();
            return new SessionStateStoreData(foo, bar, 300);
        }
        public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
        {
            locked = false;
            lockAge = TimeSpan.FromSeconds(10);
            lockId = new object();
            actions = SessionStateActions.None;
            ISessionStateItemCollection foo = new SessionStateItemCollection();
            HttpStaticObjectsCollection bar = new HttpStaticObjectsCollection();
            return new SessionStateStoreData(foo, bar, 300);
        }
        internal virtual void Initialize(string name, NameValueCollection config, IPartitionResolver partitionResolver) { }
        public override void InitializeRequest(HttpContext context) { }
        public override void ReleaseItemExclusive(HttpContext context, string id, object lockId) { }
        public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item) { }
        public override void ResetItemTimeout(HttpContext context, string id) { }
        public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) { }
        public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback){return true;}
    }
}

全球.asax:

    protected void Session_Start(object sender, EventArgs e)
    {
        throw new Exception("It worked!");
    }

网络配置:

    <sessionState mode="Custom" customProvider="MySessionProvider">
        <providers>
            <add name="MySessionProvider" type="WebApplication1.SessionStateProvider"/>
        </providers>
    </sessionState>

这篇文章的重点主要是说,如果您使用提供的会话管理模块,即使使用自定义提供程序,它仍然应该触发 session_start 事件。也许您可以尝试使用我的虚拟状态提供程序,看看是否会触发您的事件。我还假设您的 session_onstart 的签名实际上是正确的?(即没有参数或 (object,eventargs) )。

目前我们处于一个愚蠢的位置,因为到目前为止我们所拥有的所有信息都是错误的。我们现在留下了有关您的 sessionstateprovider 导致 session_start 不触发或您的其余代码的某些内容。使用我的假人应该可以帮助我们回答这个问题(我希望如此)。

对于它的价值, session_start 事件应该在该CreateNewStoreData方法在您的提供程序类中运行后立即被触发,因此您可以尝试在那里放置一个断点,然后查看它在该方法之后的位置。

于 2010-08-11T09:14:33.177 回答
0

我猜操作目标是做一些事情,比如初始化会话,而不是需要在 Session_OnStart 方法中专门做一些事情。假设是这种情况,我认为您可以执行以下操作:

1) 处理 Appication.PostAcquireRequestState 事件。
2)在处理程序中,检查会话是否已初始化——可怜的人的方法是在会话中设置一个变量——然后采取适当的行动。

于 2010-08-10T15:59:43.653 回答