ASP.Net会议

Ste*_*orn 24 asp.net session session-state

我想存储用户在一系列不同的ASP.Net webforms中执行的某些操作的"状态".我对持久状态的选择有哪些,每种解决方案的优缺点是什么?

我一直在使用Session对象,并使用一些帮助方法来强类型化对象:

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

    public static void SetCurrentAccount(Account obj, HttpSessionState session)
    {
        session[ACCOUNT] = obj;
    }
Run Code Online (Sandbox Code Playgroud)

很多消息来源都告诉我"会话是邪恶的",所以这才是这个问题的根本原因.我想知道你认为什么是"最佳实践",以及为什么.

Mau*_*ice 38

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

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

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


Mar*_*ham 19

临时存储表单数据的两个选择是,首先,将每个表单的信息存储在会话状态变量中;其次,使用URL参数传递表单信息.使用Cookie作为潜在的第三种选择根本不可行,原因很简单,因为许多访问者可能关闭了cookie(但这不会影响会话cookie).此外,我假设您的问题的性质,您不希望将此信息存储在数据库表中,直到它完全提交.

使用Session变量是解决此问题的经典解决方案,但它确实存在一些缺点.其中包括(1)如果使用inproc会话管理,大量数据可能耗尽服务器RAM,(2)在服务器场中的多个服务器之间共享会话变量需要额外考虑,(3)专业设计的应用程序必须防止会话到期(不要只是转换会话变量并使用它 - 如果会话已过期,则转换会抛出错误).但是,对于绝大多数应用程序来说,会话​​变量无疑是最佳选择.

另一种方法是在URL中传递每个表单的信息.这种方法的主要问题是你必须非常小心"传递"信息.例如,如果您要收集四页信息,则需要先收集信息,然后将URL传递到第二页,您必须将其存储在该页面的视图状态中.然后,在调用第三页时,您将从第二页收集表单数据和视图状态变量,并在URL等中进行编码.如果您有五个或更多页面,或者访问者将在网站上跳转,那么你手上会弄得一团糟.还要记住,所有信息都需要A)被序列化为URL安全字符串,并且B)以防止简单的基于URL的黑客的方式编码(例如,如果你把价格放在明文中并传递给它,有人可能会改变价格).请注意,您可以通过创建一种"会话管理器"来减少其中一些问题,并让它为您管理URL字符串,但您仍然必须对任何给定链接可能会吹走某个人的整个会话的可能性非常敏感.它没有妥善管理.

最后,我使用URL变量仅用于将非常有限的数据从一个页面传递到下一个页面(例如,在该项目的链接中编码的项目ID).

那么,让我们假设您确实使用内置的Sessions功能管理用户的数据.为什么有人会告诉你"会话是邪恶的"?好吧,除了上面提到的内存负载,服务器场和到期考虑因素之外,对Session变量的主要批评是,它们是有效的无类型变量.

幸运的是,谨慎使用Session变量可以避免内存问题(无论如何都应该在数据库中保存大项),如果运行的站点足够大,需要服务器场,那么有很多机制可用于共享内置于ASP的状态.NET(提示:您不会使用inproc存储).

为了避免几乎所有Session的其余缺点,我建议实现一个对象来保存会话数据以及一些简单的Session对象管理功能.然后将它们构建为Page类的后代,并将这个后代Page类用于所有页面.然后,通过页面类作为一组强类型值访问Session数据是一件简单的事情.请注意,对象的字段将为您提供一种以强类型方式访问每个"会话变量"的方法(例如,每个变量一个字段).

如果这对您来说是一项简单的任务,或者您想要一些示例代码,请告诉我们!


Kam*_*oij 10

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


mat*_*uma 6

至于"会话是邪恶的"......如果你在使用经典ASP开发我不得不同意,但ASP.NET/IIS做得更好.

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

其他小花絮不需要任何长期持久性的信息,我们使用cookie和视图状态的组合.


ale*_*edy 6

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


Kam*_*oij 5

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

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