10

我正在开发的网站非常以数据为中心。有些报告需要一个多小时才能完成。每当用户提交报告请求时,都会创建一个新线程来生成报告。然后用户被重定向到一个页面,该页面显示报告正在进行中,并请刷新以下载报告。如果用户再次刷新页面并且报告仍在进行中,则会显示相同的消息;否则提供下载链接。

所有报告/用户关系都保存在应用程序变量中。这很好用,除非用户处于非活动状态超过 20 分钟(正在处理报告时),然后用户被注销;如果用户再次登录,仍然可以下载报告。

我不想增加会话过期时间,但如果用户在后台有事情发生,我需要停止过期,比如正在处理的报告。

在 Session_End 我可以检索userid并匹配它Application["work"]以查看用户是否有待处理的工作。

但是,我不知道如何在上述情况下推迟会话结束?


编辑:每个人都建议作为从“维护联系人”到“使用查询字符串”的解决方法。“保持联系”对我来说看起来最有希望,但在以下情况下它会失败:当浏览器关闭/计算在午餐等期间进入待机模式。 b.当用户转到另一个非 asp.net 部分(它是一个旧站点)时。

难道不能取消Session_End活动本身吗?

4

10 回答 10

6

简短的回答

目前(我所知)没有简单的方法可以延长单个ASP.NET 会话的寿命。有一种可能的解决方案:使用自定义的 Session-State Store Provider!


长答案

首先要做的事情:从已经构建的东西开始!使用Microsoft 提供的示例Session-State Store Provider及其教程)。此示例 Session-State Store Provider使用 Microsoft Access 作为其后端;不过,由于它使用 ODBC 连接,因此您几乎可以通过已安装的 ODBC 驱动程序支持任何数据库后端。

此示例会话状态存储提供程序只是 ASP.NET 内部使用的自定义版本(ASP.NET 在内存中运行的例外)。


其次:让我们准备 Access 数据库的要求和配置。

按照教程和文件注释中的说明创建表:

CREATE TABLE Sessions
(
    SessionId       Text(80)  NOT NULL,
    ApplicationName Text(255) NOT NULL,
    Created         DateTime  NOT NULL,
    Expires         DateTime  NOT NULL,
    LockDate        DateTime  NOT NULL,
    LockId          Integer   NOT NULL,
    Timeout         Integer   NOT NULL,
    Locked          YesNo     NOT NULL,
    SessionItems    Memo,
    Flags           Integer   NOT NULL,

    CONSTRAINT PKSessions PRIMARY KEY (SessionId, ApplicationName)
)

注意:如果要使用 SQL Server,只需将Text(...)替换为varchar(...)将 YesNo 替换bit,将Memo替换为varchar(MAX)

使用以下内容添加/更新您web.config的(您可以使用connectionstrings.com帮助您生成连接字符串):

<configuration>
    <connectionStrings>
        <add name="OdbcSessionServices" connectionString="DSN=SessionState;" />
    </connectionStrings>

    <system.web>
        <sessionState 
                cookieless="true"
                regenerateExpiredSessionId="true"
                mode="Custom"
                customProvider="OdbcSessionProvider">
            <providers>
                <add name="OdbcSessionProvider"
                        type="Samples.AspNet.Session.OdbcSessionStateStore"
                        connectionStringName="OdbcSessionServices"
                        writeExceptionsToEventLog="false" />
            </providers>
        </sessionState>
    </system.web>
</configuration>

第三:添加一个将扩展超过指定的函数Timeout

制作函数的副本ResetItemTimeout,并将其命名为ResetItemTimeout2

var ExtendedTotalMinutes = 2 * 60; // hours * minutes

public override void ResetItemTimeout2(HttpContext context, string id)
{
    OdbcConnection conn = new OdbcConnection(connectionString);
    OdbcCommand cmd = 
        new OdbcCommand("UPDATE Sessions SET Expires = ? " +
            "WHERE SessionId = ? AND ApplicationName = ?", conn);
    cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value 
        = DateTime.Now.AddMinutes(ExtendedTotalMinutes); // IMPORTANT!! Set your total expiration time.
    cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id;
    cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName;

    try
    {
        conn.Open();

        cmd.ExecuteNonQuery();
    }
    catch (OdbcException e)
    {
        if (WriteExceptionsToEventLog)
        {
            WriteToEventLog(e, "ResetItemTimeout");
            throw new ProviderException(exceptionMessage);
        }
        else
            throw e;
    }
    finally
    {
        conn.Close();
    }
}

第四:支持单个ASP.NET Session的扩展!

每当您需要扩展会话时,请ResetItemTimeout按如下方式调用该函数:

using Samples.AspNet.Session;

// from inside a User Control or Page
OdbcSessionStateStore.ResetItemTimeout2(this.Context, this.Session.SessionID);

// --or--

// from anywhere else
OdbcSessionStateStore.ResetItemTimeout2(System.Web.HttpContext.Current, System.Web.HttpContext.Current.Session.SessionID);

脚注

  1. 使用示例 Session-State Store Provider阅读页面上的评论;

    • 使用 GetItem 时,有一个关于GetSessionStoreItem 错误的潜在好条目。

    • 另一个好处是Timestamps 应该是 UTC

  2. 可以进行明显的性能/可维护性改进(尤其是在 和 中有重复代码的情况下ResetItemTimeoutResetItemTimeout2

  3. 没有测试过这段代码!


编辑

  • 我意识到我错过了您想要扩展的部分-答案Timeout已完全更新。
  • 添加脚注部分。
于 2013-04-04T15:47:28.980 回答
4
Maintain a contact with the server will avoid Session Timeout. 

创建一个empty Web service然后按几秒钟的间隔run that in your servercall the web service by your site by JQuery足以使会话保持活动状态

可能这个解决方案会帮助你..

尝试此链接以获取完整详细信息:防止 ASP.NET 中的会话超时

于 2013-04-01T11:40:43.697 回答
4

当您检测到已请求需要很长时间的报告时,您可以将会话超时设置为更高的值。这当然假设您可以计算报告是否需要很长时间才能运行。如果是这样,您可以在启动线程之前执行此操作:

Session.Timeout = 120 // set timeout to two hours for this session only

除了通过 Ajax ping 页面或服务之外,确实没有其他方法。(除非完全不依赖会话是一种选择)。

这是因为会话的维护方式:当请求包含 cookie 时,ASP.NET 运行时检测到会话。此 cookie 在每个请求/响应中设置,并将包含到期日期。

如果在您的初始请求中设置了 20 分钟的到期时间并且用户关闭浏览器或处于非活动状态超过 20 分钟,则服务器端无法检测到请求属于哪个会话。因此,要回答您是否可以取消 session_end 的问题,不,您不能这样做,因为该代码运行服务器端并且它无法访问客户端 cookie。这是一个简单的事件,在您最后一次设置 cookie 后 20 分钟触发。这与客户端完全异步。

我提出的解决方案是一种解决方法,如果您知道如何计算持续时间(至少近似地),它可能会起作用。

另一种更复杂的解决方案是保存报告并为用户创建一个单独的部分,用户可以在其中查看所有报告。这样,即使会话超时,他也可以重新登录并转到他的历史记录并检索报告。

于 2013-04-03T11:36:45.733 回答
3

在拼命寻找推迟 session_end 事件的同时,我认为这似乎是不可能的?

我能想到的最简单的解决方法是“使用 Cookie”并修改我的身份验证逻辑。

我实现了一种方法,用于在用户请求 9 小时到期的报告时将 guid 密钥写入名为 admin 的 cookie(Max time office 将开放工作)。我将此带有用户 ID 的 guid 保存在单独的表中。

在我检查会话用户 ID 的母版页中,我实现了另一种方法来检查任何名为 admin 的 cookie。如果找到它,我将会话设置为保存在表中的用户 ID,否则我将它们重定向到登录页面,就像它发生之前一样。

它似乎像魔术一样工作。但我需要知道这是对的吗?

于 2013-04-04T07:18:51.063 回答
3

最好不要依赖 Session_end 因为它并不总是触发,例如当工作进程回收或发生未捕获的异常时,即它基本上被杀死/反弹。

如果您想恢复会话,那么最好的方法似乎是以某种方式存储用户数据并自己完全管理缓存。

从您对之前帖子的回复看来,使用 sql 状态管理时额外的网络活动和后续页面时间负载增加是不可接受的,使用 sql server 状态提供程序与使用Microsoft AppFabric等会话服务器之间的差异可以忽略不计,但是如果您使用 AppFabric 的会话服务器以及它的缓存,这似乎是一种明显的可能性,事情可能会加快很多。

PS 一般来说,取消会话似乎是最有效的解决方案,请参阅 John Han 在这篇文章中的回答,总结会话是不好的 mmkay

于 2013-04-10T08:13:07.273 回答
2

为了使会话保持活动状态,某些东西(不一定是用户的浏览器)必须每隔一段时间使用该用户的 ASP.NET_SessionId cookie 向您的应用程序发出请求。

如果您有一些代码可以保存您感兴趣的用户的 ASP.NET_SessionIds,然后有一个 Windows 服务会每隔 20 分钟左右在您的应用程序上请求一个具有所需 ASP.NET_SessionId(s) 的页面。

有关此 cookie 的一些信息,请参阅http://erlend.oftedal.no/blog/?blogid=41

于 2013-04-09T15:45:01.360 回答
2

你在使用 FormsAuthentication 吗?如果是这样,您可以增加身份验证票证的超时时间,这将阻止登录屏幕,即使在会话过期后也是如此。

在请求开始时,您可以通过票证检查用户在获​​取用户后,如果会话为空,则表示该用户已离线一段时间,您可以检查该用户正在进行的工作。

如果用户有正在进行的工作,请加载您可能需要的会话值并将它们重定向到正在进行的工作或报告以供下载。

如果用户一无所有,请将票证过期并将其重定向到登录页面,或者只是让他们保持登录状态并重新加载会话值。

身份验证票的超时非常大 http://msdn.microsoft.com/en-us/library/system.web.configuration.formsauthenticationconfiguration.timeout.aspx

干杯

于 2013-04-09T15:58:42.517 回答
1

我建议增加会话超时而不是试图找到解决方法。这里有一个关于会话和表单超时的有趣线程

于 2013-04-01T11:22:13.007 回答
1

我建议您根本不依赖会话 .. 您可以通过添加一个新的 GUID 变量来依赖查询字符串,并将该变量值与应用程序对象一起使用,以将用户请求的文件与 GUID 值映射。 . 这样 .. 用户将始终能够下载文件,因为他拥有映射到应用程序对象的文件的链接,并且无需处理任何会话超时。

于 2013-04-01T11:48:26.730 回答
1

您为什么不尝试显示加载文件进度条,在其中您可以使用检查目前已下载文件状态的逻辑。它将有两个优点,当您访问您的网站时,会话不会在您将有用信息返回给最终用户的同时过期。

于 2013-04-01T13:31:19.947 回答