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

时间:2014-05-02 00:39:58

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4 session session-variables

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

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

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

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

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

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

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

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

在提供最佳建议方面似乎相互矛盾的2个帖子让我有些困惑。

缺点:Is it a good practice to avoid using Session State in ASP.NET MVC? If yes, why and how?

优点:Still ok to use Session variables in ASP.NET mvc, or is there a better alternative for some things (like a cart)

似乎这个问题(尽管有很多不同的版本)都没有明确的答案我可以得出结论。

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

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

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

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

由于

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

对提供的答案的更新回复

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

对Tim表示赞赏,它表示数据库存储已经过优化,用户可以选择稍后返回并继续他们离开的地方。

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

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

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

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

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

我更具体地寻找的是一种能够轻松适应不同场景的技术的普遍共识。换句话说,这些东西不仅可以适应我的特定场景,还可以为具有潜在更大流量的大型环境提供可扩展性元素。通过这种方式,编程的变化可以完全缓解,也可以最小化。

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

基于反馈的摘要:

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

  2. 缓存优于会话变量,但同样不一定是"最佳"由于以前指出的Web服务器场环境中潜在的同步复杂性等原因导致的可扩展选项。但仍然是一个选择。

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

  4. Cookie似乎是一个很好的选择,结合了#34;理想的"会话变量和缓存的元素。

  5. =============================================== ===

    结论

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

    2之间的最终选择似乎是基于需要存储的数据的数量和类型(例如,敏感与非敏感以及是否存在客户可能改变其数据的担忧);除了COOKIES的特殊注意事项,因为它们可能会被客户禁用。

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

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

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

    谢谢大家!

3 个答案:

答案 0 :(得分:24)

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

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

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

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

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

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

答案 1 :(得分:9)

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

但是,如果您排除了其他机制,那么小的,逐个用户的值是会话的可行候选者。

Cache适用于网站范围的值,或具有唯一键的用户特定值。但是,跨多个Web服务器同步缓存可能很困难。进程外会话状态将保持同步,因为它存储在单个位置(数据库或状态服务器)。

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

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

性能

如果您使用进程外会话状态(例如在负载平衡环境中和/或使会话更持久),命中数据库或调用进程外服务,但是除非你序列化大型对象图,否则调用相对便宜。

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

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

装饰控制器

设计

  

现在我通过分配值成功完成了这项任务   到我的_layout视图中检索的Session变量;

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

  

我在某处读到了与Global.ascx一起使用MVC过滤器的地方   应用程序启动部分,但这似乎不合适   对于在控制器级别设置的变量,可能是静态的   变量

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

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

答案 2 :(得分:3)

不同角度的会议选择: -

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

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

  1. 缓存: - 在会话中存储列表或类似大数据的内容更适合缓存。您可以随时控制它而不是用户会话。

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