Global.asax Session_End没有使用enableSessonState = ReadOnly在Session.Abandon()上触发

时间:2014-12-18 09:45:34

标签: asp.net session

我在通过Global.asax.Session_End()终止ASP.Net会话后,尝试通过Session.Abandon()执行清理任务。

我已确保以下

  • SessionStateMode是 InProc
  • 我将数据写入SessionDataStore (Session["foo"] = "bar"
  • 会话创建和.Abandon()在不同的请求中执行,会话保持不变

现在我遇到以下行为: 当我将会话全局写入(web.config中为enableSessionState = true)时,我Global.asax.Session_End()会在Session.Abandon()之后不久按预期触发。

但是,当我在web.config中设置enableSessionState = ReadOnly并且只允许某些页面通过EnableSessionState="true向会话添加数据时,例如

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="WebPages_Login" EnableSessionState="true"%> 
Global.asax.Session_End()之后不会触发

Session.Abandon(),但仅在会话超时后触发。

如何在全局设置Global.asax.Session_End()的{​​{1}}上触发Session.Abandon()

2 个答案:

答案 0 :(得分:1)

我不得不深入研究这个问题。

当从具有EnableSessionState = ReadOnly的页面触发Session.Abandon()时,InProcSessionState未标记为已锁定(_locked = false)。

仅当触发Session.Abandon()的请求的EnableSessionState = true时才会发生这种情况

来自System.Web.SessionState.InProcSessionStateStore.DoGet(...):

if (exclusive) {
                lockedByOther = true;

                // If unlocked, use a spinlock to test and lock the state.
                if (!state._locked) {
                    state._spinLock.AcquireWriterLock();
                    try {
                        if (!state._locked) {
                            lockedByOther = false;
                            state._locked = true;
                            state._utcLockDate = DateTime.UtcNow;
                            state._lockCookie++;
                        }
                        lockId = state._lockCookie;
                    }
                    finally {
                        state._spinLock.ReleaseWriterLock();
                    }
                }

如果会话被放弃,System.Web.SessionState.SessionStateModule.OnReleaseState()将为会话触发_store.RemoveItem()。但是,如果当前的InProcSessionState被锁定,则仅执行此RemoveItem()。请参见InProcSessionStateStore.RemoveItem():

            try {
            /* Only remove the item if we are the owner */
            if (!state._locked || state._lockCookie != lockCookie)
                return;

            /* prevent overwriting when we drop the lock */
            state._lockCookie = 0;
        }

因此,在这种情况下(EnableSessionState = ReadOnly),Session.Abandon()根本不会放弃会话。看起来像是一个ASP.Net错误。

因此,我必须做的是两次触发清理代码:

  • 直接调用System.Abandon()的地方
  • Global.asax.Session_End()中的
  • 用于超时会话

答案 1 :(得分:1)

我对OP有类似的设置。我的应用程序中的一些处理程序使用只读会话状态。但是,我发现.NET中的事件名称显然发生了变化(https://msdn.microsoft.com/en-us/library/ms178583.aspx)。在实现Session_OnStart和Session_OnEnd之后,我的会话被正确终止并且调用Session_OnEnd。我不会在会话状态中存储任何项目。所以我认为没有必要。