从自定义ASP.NET SessionStateProvider类中提升Session_OnStart事件

时间:2010-08-04 22:30:03

标签: asp.net events session global-asax session-state-provider

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

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

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

更新:它在MSDN上明确指出,Session_OnStart通常仅在会话模式为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并删除了自定义SessionIDManager的代码。一旦我这样做,我立即能够看到Session_OnStart方法执行。问题是,我的自定义SessionStateProvider 需要自定义SessionIDManager。从Session_OnStart事件发生的确切位置是什么?它看起来与SessionIDManager有关,而不是SessionStateProvider

3 个答案:

答案 0 :(得分:1)

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

对不起,这是一个答案,因为我不是100%肯定我在说什么,但它太长了,无法发表评论......

我不确定您是否已创建自定义会话模块或jsut会话状态存储提供程序。我假设模块,但我不确定只是“SessionStateProvider”......

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

所以从本质上讲,如果您的新模块包括在内:

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

然后你想要你的global.asax MySession_Start

我希望这会有所帮助。对不起,如果没有,以及你之前尝试过的所有东西。我建议给出一些代码以及你已经尝试过的一些想法,但是它会失败。可能有趣的代码是将自定义代码添加到站点中(即web.config的相应部分),也可能是会话类中的一些代码,如果它可以轻松地缩小到一个简单的形式(例如会话提供程序,只返回一个常量可以很短并证明你的错误)。还有一些关于它是否保持会话状态的指示(即它是否工作分开而不是调用onstart)将是好的。 :)

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

答案 1 :(得分: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;}
    }
}

的Global.asax:

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

的web.config:

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

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

目前我们处于一个公开的位置,因为到目前为止我们所掌握的所有信息都是错误的。我们现在留下了关于你的sessionstateprovider的任何东西导致session_start不会触发或者其他代码的内容。使用我的假人应该帮助我们回答这个问题(我希望)。

在您的提供程序类中运行CreateNewStoreData方法之后,应该触发session_start事件的值得,因此您可以尝试在那里放入一个断点,并在该方法之后查看其前进的位置。 / p>

答案 2 :(得分:0)

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

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