首页 文章

在 MVC 中是否有最佳实践和推荐的 Session 变量替代方法

提问于
浏览
44

好吧,首先,在任何人试图确定这是一个“重复”的问题之前;我已经回顾了关于类似问题的大部分关于 SO 的帖子,但即使结合所有已经说过的话,我仍然有点处于最终的困境,或者我应该就此达成一致意见。

然而,我可以说我(基于帖子)最终确定答案是基于要求的范围。但即使考虑到这一点,我的意见似乎也太多了,我无法决定如何处理这个问题。

我的直接要求是我需要在许多视图中保持来自 1 个控制器的可变数据。更具体地说,我有一个控制器和相应的视图来处理购物车项目计数,我想在多个视图中保留这些数据。我认为_layout 视图是最合乎逻辑的选择。

现在我已成功完成此任务,方法是将值赋给从我的_layout 视图中检索的 Session 变量;因此,即使用户要浏览网站内的任何位置,购物车中的商品数量仍将持续,直到他们离开网站或完成结帐;在这种情况下,变量将在代码中清除。

我读过的帖子似乎偏向于远离 Session 变量而支持 Cookie 并将数据存储在数据库中;或者声明为了我建议使用它们的目的,Session 变量可以很好地使用。

我读过的另一件事表明,如果网站上的流量很高,会话变量可能会阻碍整体性能,因为信息存储在服务器上。

我个人无法证明在数据库中存储此类信息并随后访问数据库是合理的,因为我认为这也会影响网站性能,并且对于临时数据的存储似乎有点过分。 TempData,ViewData 和 ViewBag 不能用于持久保存数据,因此它们不是 IMO 要求的逻辑选择。

如果还有另一个非常适合 Session 变量的替代品(这对我有用),我想知道它是什么。

2 posts 似乎与提供最佳建议的努力相矛盾让我有点困惑。

缺点:避免在 ASP.NET MVC 中使用会话状态是一种好习惯吗?如果是,为什么以及如何?

优点:还是可以在 ASP.NET mvc 中使用 Session 变量,或者对某些东西(比如购物车)有更好的选择

似乎这个问题(虽然以许多不同的变体形式呈现)没有明确的答案,我可以得出结论。

如果有一种更优选的方式来实现这一点而没有过度杀伤,那么这就是我正在寻找的答案。

我在某处读到了与 Global.ascx 应用程序启动部分一起使用 MVC 过滤器,但这似乎不适合在控制器级别设置的变量,也许与静态变量一样多。

有人可能会对这个主题提出许多不同的意见(可能是因为缺少一个更好的词)吗?也许可以为这个问题提供更明确的答案?我确信各种各样的意见都有它们的位置,我并不是在试图抹黑它们。但是,拥有明确且可能一致的答案会更好;然后我可以对其他帖子进行排序,以确定最适合我的应用程序的内容。

当然,如果这个问题没有明确的答案;告诉我,我会尝试从其他帖子中得出我自己的答案。

谢谢

===========================================================

对提供的答案的更新回应

缓存和 Cookie 似乎是响应的一般偏好,但我也注意到缓存它不是在多个 Web 服务器上使用的理想候选者的声明,因为同步可能是一个潜在的问题。

值得称赞的是 Tim,它表示数据库存储已经过优化,用户可以选择稍后返回并继续停止。

这是一个很好的观点,但对可能性保持远见;一些用户可能无法返回,在数据库中留下不必要的数据,这可能是合理的。

因此,保持数据库优化和清洁(“对我而言”具有相同的相关性)将需要实施维护任务,以根据设定的时间阈值自动使这些记录到期以考虑这些情况。虽然维护任务不是一个不容置疑的选择,但我仍然认为这仅仅为了作为临时存储的意图目的而增加了一些工作量。

尽管如此,我确实尊重蒂姆的建议,并认为在一定程度上反对我的初步意见是值得的。数据库似乎不是存储临时数据的可行选择;所以我认为折衷方案是将数据存储在数据库中(考虑到购物车或类似的场景),可能是在结账后。正如您之前所述,这种方式可能会在后续访问时持续跟踪数据,因此您可以记录交易记录。但更重要的是,这些事务的数据与持久存储到数据库中具有真正相关性。

还有人说,尽管 Session 比数据库快;但是,尽管有一些警告可以在某种程度上通过其他机制来缓解,例如利用 SessionStateBehavior 属性,仅作为一个例子。

但是......我认为 Erik 有点用 Dunning-Kruger 效果驱使回家。虽然,从这里给出的答案的内容和解释;我严重怀疑任何回应的人的专业知识是否有问题。尽管如此,我倾向于同意这样一个事实:获得一致意见可能比我的合理期望高一些。

我更具体地寻找的是对一种技术的普遍共识,该技术可以舒适地适应不同的场景。换句话说,这些东西不仅可以适应我的特定场景,还可以为具有潜在更大流量的大型环境提供可扩展性元素。这样,编程的改变可以完全减轻或最小化。

==================================================

根据反馈摘要:

  • 会话变量似乎适应较小的案例场景,并且在适用的情况下,但它们有一些潜在的持久性问题,以及其他值得注意的差异,如 Erik 所说的非常彻底。所以这个选项显然不适合可扩展的模型。

  • 缓存优于会话变量,但同样不是“最佳”可伸缩选项,这是由于 Web 服务器场环境中潜在的同步复杂性,如前所述。但仍然是一个选择。

  • 数据库存储是可扩展的,但出于临时易失性存储的目的,从数据库的角度来看可能不是最优雅的选择,因为它需要定期清理。就个人而言,在我职业生涯早期拥有强大的数据库概念基础,这可能不会成为许多开发人员可能同意的事情。但是从程序员的角度来看,为此目的使用数据库可能足以满足 Web 开发的需要;但是从 DAL 和 DB 开发的角度来看,这(对我而言)有可能强制执行额外的 DB 任务来强制执行有效的后端。

  • Cookie 似乎是一个很好的选择,具有 Session 变量和缓存的“理想”元素。

==================================================

结论

根据答案;我认为 COOKIES 和 CACHING 似乎通常是全面的最佳实践建议,结合数据库存储,事后需要持续的持久性;作为提供的可扩展性的潜在良好候选者。

2 之间的最终选择似乎是基于需要存储的数据的数量和类型(e.g. 敏感 vs non-sensitive 以及是否有任何担心客户可能会改变他们的数据);除了 COOKIES 的特殊考虑之外,它们可能会被客户禁用。

显然,从提供的答案中明确指出并得出结论,但在可扩展性方面,没有一个适合所有解决方案的解决方案;我可能错了,但这些似乎是最好的选择。

因为所有的反应都很好;我相当赞同所有帖子都有用,并接受 Erik 的答案作为一个全面的整体可扩展解决方案。我希望我可以选择多个已接受的答案,因为我相信蒂姆的回答也非常清晰和简洁。

古普塔的反应也不错,但我想更详细地提出建议的答案,而不是重复以前的帖子。

多谢你们!

3 回答

  • 24

    你永远不会对任何一大群人的任何事情达成一致意见。那只是人性。其中一部分源于Dunning-Kruger 效果,其中指出某人对某一主题知之甚少,他们越有可能过分重视他们在该主题上的专业知识。换句话说,很多人认为他们知道某些事情,但仅仅因为他们不知道他们不知道。部分原因是人们有不同的经历,有些人发现会话没有问题,而有些则有不同的情况,反之亦然......

    因此,为了备份您的研究,这表明答案在很大程度上取决于要求,我们需要了解您的要求是什么。如果这是一个高流量站点,在 Web 场中使用负载平衡服务器,则尽可能远离会话。当然,可以在服务器场环境(会话服务器,分发缓存服务器,etc..))中以各种方式共享会话,但如果可以帮助它,则避免会话几乎总是更快。

    如果您的站点是单个服务器,并且不太可能超出该服务器。而且您的流量模式相对较低,那么会话可能是一个有用的选择。但是,您应始终注意会话存储不可靠,并且可能随时消失。如果应用程序池被回收,会话就会消失。如果未捕获的异常冒泡到工作进程,则会话可能会消失。如果 IIS 认为内存不足,则无论配置了什么超时值,您的会话都可能会消失。您也无法始终获得会话已结束的可靠通知,因为已终止的会话不会触发 Session_End 事件。

    另一个问题是 Session 是序列化的。换句话说,IIS 一次阻止多个线程写入会话,并且它通常通过在线程运行时锁定会话(如果它没有选择退出可写会话锁定)来执行此操作。这在某些情况下会导致严重的问题,而在其他情况下则会导致性能不佳。如果您不打算在该方法中修改它,可以通过使用 read-only 会话属性标记各种方法来缓解此问题。

    最终,如果您确实选择使用会话,那么尽量只使用它来处理小的,短暂的事情,如果不可能的话,那么如果会话丢失,则构建一种“重新生成”数据的方法。例如,使用购物车示例中的项目数量,您可以编写一个方法,首先检查该值是否存在,如果不存在,则将其从数据库中加载。始终使用此方法来访问变量,而不是直接从会话访问它...这样,如果会话丢失,它只会重新加载它。

    但是,说了这个...对于购物车中的商品数量,我通常更喜欢使用 cookie 来获取此信息,因为 cookie 无论如何都会在每次加载时传递到页面,这是一个小的离散数据单元。对于您希望阻止用户无法更改的敏感数据,通常更喜欢会话。购物车中的商品数量根本不符合该规则。

  • 9

    什么时候

    数据库经过高度优化。像购物车计数这样的简单值是数据库缓存的一个很好的候选者,并且(希望)可以廉价地直接计算。它可能是 non-issue。

    但是,如果您排除了其他机制,那么小的 user-by-user 值是会话的可行候选者。

    Cache适用于 site-wide 值,或 user-specific 值适用于唯一键。但是,跨多个 Web 服务器同步缓存可能很困难。进程外会话状态将保持同步,因为它存储在单个位置(数据库或状态服务器)中。

    当然,有许多第三方缓存备选方案可以使它们保持同步。

    无论计数临时存储在何处,我都认为购物车本身应存储在数据库中,以便用户可以选择稍后返回并继续停止。

    性能

    如果您使用进程外会话状态(e.g. 在负载平衡环境 and/or 中以使会话更耐用),它将命中数据库或调用进程外服务,但除非您序列化大对象图,否则调用相对便宜。

    每个请求加载一次会话。后续读取访问速度非常快。

    即使没有负载,写入会话也可能对性能有害。为什么?大多数现代应用程序使用异步调用,当多个异步调用命中 HTTP 处理程序(页面,控制器等)reads/writes session 时,ASP.Net 将锁定会话以序列化访问。为避免这种情况,您可以使用[SessionState( SessionStateBehavior.ReadOnly )]装饰控制器

    设计

    现在我已成功完成此任务,方法是将值赋给从我的_layout 视图中检索的 Session 变量;

    这似乎是混合问题,i.e。让视图意识到底层存储机制。从纯粹主义的角度来看,我会在视图模型上设置此值,或者至少将其放在ViewBag中。从实际的角度来看,以这种方式检索的一个或两个值可能不会伤害任何东西,但要注意让它进一步增长。

    我在某处读到了与 Global.ascx 应用程序启动部分一起使用 MVC 过滤器,但这似乎不适合在控制器级别设置的变量,也许与静态变量一样多。

    静态变量具有完全合法的用途,但您必须彻底了解它们或存在严重问题。

    请参阅 ASP.Net 中有关静态变量的答案:

  • 3

    不同前景的会议选择: -

    当您在会话中保留某些内容时,它会破坏 ASP.NET MVC 中的主要规则。您可以使用这些选项作为会话的替代方案。

    如果您的 asp.net(MVC)会话在对象上进行装箱拆箱,那么它会对服务器造成一些负担。尝试这个想法

    • 缓存: - 在会话中存储列表或类似大数据的东西更适合缓存。只要您希望它过期而不是用户会话,您就可以控制。

    • 如果您的应用程序依赖于 JSON/Ajax 数据,那么您可以使用 html5 中提供的某种功能(如 WebSQL,IndexDB)。它不会使用 cookie,因此您可以在服务器上节省一些工作量。

相关问题