【问题标题】:Where's the best place to store a custom "User" object for the duration of an ASP.NET session?在 ASP.NET 会话期间存储自定义“用户”对象的最佳位置在哪里?
【发布时间】:2010-07-06 07:58:56
【问题描述】:

我有一个 ASP.NET 应用程序,它需要在会话中跨页面记住有关用户(以及他们来自哪家公司)的一些信息。

我想这几乎是任何特定大小的 ASP.NET 应用程序的要求。这些年来,我使用了几种不同的方法。

过去,我在查询字符串参数中传递了一个 id,如下所示:

site.com/page.aspx?usrid=1&companyid=2

然后实例化每个页面上的对象(来自数据库)。

另一种常见的做法是将我的对象存储在会话变量中:

Session["User"] = currentUser;              // store at login
User currentUser = (User)Session["User"];   // retrieve on some other page

这节省了访问数据库的时间,但如果用户对象很复杂并且站点有很多并发用户,我会担心使用的内存。

我最近继承了一个使用母版页上公共属性的应用程序,如下所示:

Master.theUser = currentUser;         // store at login
User currentUser = Master.theUser;    // retrieve on some other page

这节省了演员表,而且我认为对我来说看起来更具可读性,但我不知道它在性能方面是更好还是更差。它在 getter 中也有一些逻辑,如果私有值为 null,它会尝试从 Session 变量中获取它,但我不确定它是否从未使用过(或使用 every get!? ) 或什么。

我最近的想法是使用我的页面类。我有一个从标准 System.Web.UI.Page 基类派生的自定义页面类。它包括像 CurrentUser 这样的对象作为公共属性。这似乎工作正常。我更喜欢它。

但我真的不知道幕后发生了什么。任何人都可以就哪种方法更好以及为什么提出意见?

也欢迎对此提出其他建议。

更新: 我已经对使用 trace.axd 和 Trace.Write 进行了一些检查,它看起来既不是母版页版本,也不是自定义页面类版本“记住”页面之间的值。 “get”方法有一行代码检查 User 属性是否为空,如果是,则从会话变量中读取它。当页面在给定页面上第一次访问属性(Master.User 或派生类的 this.User)时会发生这种情况,然后后续请求可以获取该值(无需转到会话变量)。

【问题讨论】:

  • 仅供参考,性能应该在您的关注列表中较低。从 Session 中拉出对象的开销极低。易用性和封装性很重要,优化不重要。

标签: asp.net master-pages session-state derived-class


【解决方案1】:

Session 正是为此目的而设计的。它存储用户“会话”生命周期的相关数据,我认为是 20 分钟或用户关闭浏览器。如果您关心您的用户对象的大小,您可以只存储 ID,然后从数据库中检索对象,但您必须权衡数据库往返的权衡。但是,我认为它通常与 Session 无关,因为它不像 ViewState 那样发送给客户端。您还可以使用 Curious Geek 示例中的属性公开此会话值,但使用 Session 对象而不是 ViewState 对象。

在母版页上设置属性将不起作用,因为它只是当前实例化类的成员,它会在每个请求结束时收集垃圾,因此您不会在下一个请求中使用它。

下面是 ASP.NET 中状态管理的总结: http://msdn.microsoft.com/en-us/library/75x4ha6s.aspx

【讨论】:

    【解决方案2】:

    我同意你latest 的想法。让公共页面基类公开您的user 类型的公共属性。该属性应该从/向会话密钥读取/写入。我们还有另一个名为 GoBackPage 的属性,它将上一页的 URL 存储在当前页面的视图状态中。

        public string GoBackPage
        {
            get
            {
                return this.ViewState["__PrevPage"].ToString();
            }
    
            set
            {
                this.ViewState["__PrevPage"] = value;
            }
        }
    

    您仍然可以超越这一点,仅将 UserId 存储在视图状态中,并在公共页面基类中公开一个属性,该属性将从视图状态中读取 UserId 并返回 User对象。

    【讨论】:

    • 将 UserId 存储在 ViewState 中不会跨页面保留它。它只会在该页面的回发中可用(即使它在基类中)。
    • 我不会在视图状态中存储用户信息:1) 使用 ViewState 会增加必须返回给客户端的数据量。 2) 由于视图状态是客户端且不安全,因此您可以加密视图状态,但这也会对性能造成巨大影响。使用会话是要走的路!
    【解决方案3】:

    到目前为止,最好的解决方案如下所示:

    public class MyPage : System.Web.UI.Page
    {
    
    
    private User user;
    public User User
    {
        get
        {                   
            if (user == null)
            {
            user = (User)HttpContext.Current.Session["CurrentUser"];    //check if session[CurrentUser] is null here and log them out if so?
            }
            return user;
        }
        set
        {
            user = value;
            HttpContext.Current.Session["CurrentUser"] = value;
        }
    }
    
    }
    

    然后在任何webpage.aspx.cs上,你都可以这样做:

    UsernameTextBox.Text = User.FullName;
    

    第一次使用时会命中 Session,但后续使用特定页面响应会更快。

    各种类和代码隐藏中的代码现在看起来更整洁了,因为我不需要每次使用它时都从 Session 读取和转换我的 User 对象(和 Company 对象等)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-26
      • 2011-01-14
      • 1970-01-01
      相关资源
      最近更新 更多