我想储存的"状态"的一些行动的用户正在执行一系列不同的ASP.Net web表单.我有什么选择坚持状态,以及什么是优点/缺点的每一个解决方案吗?

我一直在使用会议的对象,并使用了一些辅助方法,以强烈类型的对象:

    public static Account GetCurrentAccount(HttpSessionState session)
    {
        return (Account)session[ACCOUNT];
    }

    public static void SetCurrentAccount(Account obj, HttpSessionState session)
    {
        session[ACCOUNT] = obj;
    }

我已经告诉过许多来源,"届会邪恶",这样,是真正的根本原因,这个问题。我想知道你在想什么"最佳做法",以及为什么。

有帮助吗?

解决方案

会话状态没有任何本质上的邪恶。

有几件事要记住,可能会咬你:

  1. 如果用户按下浏览器后退按钮,您将返回上一页,但不会还原您的会话状态。因此,您的CurrentAccount可能不是最初在页面上的内容。
  2. IIS进程可以回收ASP.NET进程。当发生这种情况时,您下一个请求将启动一个新进程。如果您正在使用进程会话状态,默认情况下,它将消失: - (
  3. 如果用户在一段时间内未处于活动状态,则会话也会以相同的结果超时。默认为20分钟,所以午餐会很好。
  4. 使用进程外会话状态要求存储在会话状态中的所有对象都是可序列化的。
  5. 如果用户打开第二个浏览器窗口,他将期望拥有第二个不同的应用程序,但会话状态很可能会在两个之间共享。因此,在一个浏览器窗口中更改CurrentAccount将在另一个浏览器窗口中执行相同操作。

其他提示

你两个选择,暂时储存形式的数据是,第一,储存各种形式的信息在会议状态变量(s)第二,通过形成信息,以及使用URL参数。用饼干作为一个潜在的第三种选择是根本不可行,原因很简单,很多你的访客可能有饼干关闭(这不会影响会议的饼干,不过).此外,我假设性质的问题,你不要将此信息存储在数据库表,直到它完全承诺。

使用会议变量(s)是经典的解决这个问题,但它不会遭受一些缺点。这些都是(1)大量数据可以使用的服务器RAM如果您使用的是inproc届会议管理,(2)交流会变量在多个服务器在一个服务器群需要额外的考虑因素,和(3)一个专业设计应用程序必须防止届会议的日期(不仅仅是投下一届会变量和使用它-如果该届会议已经过期的投会引发误差)。然而,对于绝大多数的应用,会议变量毫无疑问的路要走。

该替代方法是通过各种形式的信息以及在网址。主要问题与这种做法是,你必须要非常小心关于"通过沿"的信息。例如,如果你正在收集的信息,在四个网页,你会需要收集信息在第一、通过它在URL到第二页,在这里你必须存放在该网页的视图状态中。然后,打电话时第三页,你会收集形式的数据从第二页加上视图状态变量和编码两者的网址,等等。如果你有五个或更多的网页或者如果来访者将被跳跃的网站,只有一个真正的混乱在你的手中。记住所有的信息将需要A)将序列化URL-safe string和B)的编码的方式防止简单的基于URL黑客(例如如果你把价格在明确的文本,并通过它沿着,有人可能会改变价格)。注意,你可以减少其中的一些问题,通过创建一种"会议管理"和有管理的URL strings你,但你仍然是极其敏感的可能性,任何给定的链接可以吹走一个人的整个会议期间如果不进行适当的管理。

最后,我使用网址的变量只有通过非常有限的数据从一个网页到下一个(例如一项标识编码作为一个链接到该项)。

让我们假定,然后,你将确实可以管理一个用户的数据使用的建议的能力。为什么会有人告诉你"会议是邪恶"?好吧,除了存储器的负载服务器的农场,和过期的考虑上文提出,主要的批评届会变量,他们正、有效、无类型的变量。

幸运的是,谨慎地使用的会议变量是可以避免的存储问题(大项目应保留在数据库,无论如何)和如果你正在运行一个网站足够大的需要服务器场,有很多机制可用于共享国家建立在ASP.NET (暗示:你会不会使用inproc存储)。

为了避免基本上所有的其余部分会议的缺点,我建议实施一个对象举行会议的数据以及一些简单的会议目管理能力。然后建立这些成的后裔页类和使用此后裔页类为所有的网页。它是那么一个简单的问题,访问您的会议的数据通过网页类作为一套强类型的价值观。注意你的对象是会给你一个方式来访问你的每一个"会议可变"在一个强类型的方式(例如一个领域每个变量)。

让我知道如果这是一个简单的任务,或者如果你想要一些样品代码!

据我所知, Session 是存储此信息的预期方式。请记住,会话状态通常默认存储在进程中。如果您有多个Web服务器,或者如果重新启动IIS,则会丢失会话状态。这可以通过使用ASP.NET状态服务甚至SQL数据库来存储会话来解决。这可以确保人们恢复会话,即使他们被重新路由到不同的Web服务器,也可以回收工作进程。

其恶劣声誉的原因之一是,匆匆的开发人员过度使用UI代码中的字符串文字(而不是像你的帮助类)作为项目键,并最终得到一大堆不可测试的混杂状态。某种包装是非邪恶会话使用的入门级要求。

至于“会话是邪恶的” ...如果您使用经典ASP进行开发我将不得不同意,但ASP.NET / IIS做得更好。

真正的问题是维持国家的最佳方式是什么。在我们的例子中,当涉及到当前登录的用户时,我们将该对象存储在Session中,因为我们经常在其中引用它们的名称,电子邮件地址,授权等等。

其他少量花絮不需要任何长期持久性的信息,我们使用Cookie和viewstate的组合。

如果要存储可在Web应用程序中全局访问的信息,执行此操作的方法是 ThreadStatic 属性。这会将 Class static 成员转换为当前线程共享的成员,而不是其他线程。 ThreadStatic 的优点是您不必拥有Web上下文。例如,如果您的后端不引用 System.Web ,但也想在那里共享信息,则可以在开头设置用户的 id ThreadStatic 属性中的每个请求,并在您的依赖项中引用它,而无需访问 Session 对象。

因为它是 static ,但仅限于一个线程,我们确保其他同时访问者不会收到我们的会话。只要您确保为每个请求重置属性,这都可以。这使它成为cookie的理想伴侣。

我认为在这种情况下使用Session对象是正常的,但是如果长时间没有浏览器活动,你应该记住Session可以过期( HttpSessionState.Timeout 属性确定会话状态提供程序终止会话的分钟数,因此最好检查值回归前的存在:

public static Account GetCurrentAccount(HttpSessionState session)
{
    if (Session[ACCOUNT]!=null)
        return (Account)Session[ACCOUNT];
    else
        throw new Exception("Can't get current account. Session expired.");
}

短期信息,只需要存活到下一个请求,也可以存储在 ViewState 中。这意味着对象被序列化并存储在发送到浏览器的页面中,然后在点击事件或类似事件上将其发布回服务器。然后 ViewState 被解码并再次转换为对象,准备好进行检索。

会话不是邪恶的,它们在ASP.NET应用程序中提供重要功能,提供必须在用户的“会话”期间在多个页面之间共享的数据。有一些建议,我会说尽可能使用SQL Session管理,并确保您在会话集合中使用的对象是“可序列化的”。最佳实践是在绝对需要跨页面共享状态信息时使用会话对象,并且在不需要时不使用它。客户端无法获得该信息,会话密钥保存在cookie中,或通过查询字符串保存,或者根据其配置方式使用其他方法,然后会话对象在数据库表中可用(除非您使用InProc,在这种情况下,您的会话将有可能在重新加载网站时被吹走,或者在大多数群集环境中几乎无用)。

我认为“邪恶”来自过度使用会话。如果你只是在其中粘贴任何东西(比如使用全局变量),你最终会遇到性能不佳而且只是一团糟。

您放入会话对象的任何内容都会在会话期间保留,除非它已被清除。使用inproc和stateserver存储的内存管理不善将迫使您在必要时提前扩展。在会话中仅存储会话/用户的ID,并使用帮助程序类按需将所需内容加载到缓存对象中。这样,您可以根据我们使用的数据的频率来微调它的生命周期。 asp.net的下一个版本可能有分布式缓存(谣言)。

Session as evil:不在ASP.NET中,正确配置。是的,尽可能无国籍是理想的,但现实是你无法从这里到达那里。但是,您可以使Session的行为减少其影响 - 特别是StateServer或数据库会话。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top