【问题标题】:Persisting objects in ASP.Net Session在 ASP.Net 会话中持久化对象
【发布时间】:2012-03-25 12:31:53
【问题描述】:

我正在开发一个 ASP.Net 应用程序(内联网),它需要用户进行身份验证才能访问门户。

目前,我将 Employee 对象保存到 InProc Session State 中,一旦身份验证成功。然后在 Master Page 的 PageLoad 方法中检查 Employee 的 Session 是否为空(null),这意味着当前请求没有经过身份验证,然后我重定向到 Login 页面。

母版页加载:

if (Session["Employee"] == null) Response.Redirect("~/Login.aspx");

我还几乎在每个页面中都使用员工会话来获取有关已登录员工或其权限级别等的一些详细信息..

我的问题:

  1. 上述技术是否适合处理这种情况?
  2. 有时 Session 状态在服务器被回收(丢失),所以如果我在任何 chlid 页面的 PageLoad 中调用 Session 状态,而 Session 为空,它会抛出异常,因为 Master检查会话是否存在的页面 onLoad 方法仅在子页面 onLoad 方法之后运行。如何以及在哪里可以在统一的地方检查会话是否存在?因为我不想每次访问 Session 状态时都检查 Session 是否存在。
  3. 是否可以在会话结束后触发方法?我在 Global.asax 中尝试了 Session_End,但它不允许我调用任何方法或重定向到页面。

谢谢,

【问题讨论】:

    标签: asp.net session


    【解决方案1】:
    • 上述技术是否适合处理这种情况?

    当然,“好”是主观的。但是这种情况应该没问题。有多种方法可以处理用户跟踪,我很好奇是否有人有任何具体建议。

    • 如何以及在哪里可以在统一位置检查会话是否存在?

    我建议将用户跟踪的 Session 部分抽象为应用程序中的一个公共对象。在该对象中,您将检查 Session 是否为空,检查用户是否已登录,做出相应的响应等。然后所有页面(子页面和主页面)都应该使用该对象。

    这有几个好处:

    1. 您只需在一处编写会话逻辑。因此,您不会不断在整个应用程序的 Session 上编写条件。应用程序的其余部分只是调用公共对象上的方法。
    2. 如果您以后想将用户跟踪从 Session 转移到其他东西(例如数据库...我过去曾使用 RavenDB 和 MongoDB 之类的东西来跟踪瞬态 Web 应用程序数据,并取得了良好的效果),您只需要换一门课。应用程序的其余部分仍继续使用该公共对象。

    例如,这个类可能有这样的东西:

    public static string GetCurrentUsername()
    {
        if (Session["Employee"] == null)
            throw new SomeKindOfAuthenticationException();
        return ((EmployeeObject)Session["Employee"]).Username;
    }
    

    然后在整个应用程序中,您只需将用户跟踪对象调用为GetCurrentUsername。在Application_Error 中,您将通过重定向到登录页面来处理您的身份验证异常。 (这通常被认为比在上面的方法中为未经身份验证的用户返回一个空字符串更好。必须在整个应用程序中检查一个空字符串不断,而异常处理可能发生在一个地方。如果在这种情况下您需要特定页面重定向到登录页面,而只是不显示某些内容,请将调用包装在该页面本地的异常处理中并处理它相应地。)

    当然,请考虑一下,这主要是一个高级设计猜想,我指的不是我面前的实际实现。也许static 会导致Session 出现问题?也许您需要将Session 传递给它?你应该在哪里存储这个类?您还应该进行哪些其他错误检查?以此类推。

    • 是否可以在会话结束后触发方法?

    根据我的经验,不可靠。考虑会话可能结束的所有方式。用户可以单击具有清除会话逻辑的“注销”链接,或者他们可以放弃浏览器,或者他们的连接可能会在很长一段时间内失败,等等。Web 应用程序是被动请求/响应系统。在没有用户交互的情况下响应会话超时相当于一个正在进行的服务器端进程,而 Web 应用程序不适合这样做。

    这实际上是我尝试将这些瞬态数据存储在数据库中的原因之一。这样我就可以有一个单独的进程(例如 Windows 服务......被设计为在没有用户请求的情况下在后台持续运行的东西)监视该数据库并相应地响应事物。在这种设置中可以完成的一件事是一种手动 Session_End。一个单独的进程将轮询数据库中未在 X 分钟内看到活动的会话(例如,通过检查活动跟踪记录上的时间戳)并通过清除相关数据和执行任何其他任务来响应。

    在我看来,这将 Web 应用程序(响应用户请求)和状态跟踪(维护服务器端数据)的职责完全分开。

    【讨论】:

    • 感谢大卫的详细回答,我已经相应地更改了我的代码,我制作了一个像你的示例代码一样的静态类,但是我应该抛出哪个异常?目前,我使用 ApplicationException 和某个消息“未找到会话”,然后在 Application_Error 方法中检查内部异常的消息是否等于该消息,以便做出相应的响应。请注意,Employee 类在一个单独的项目中,而不是在 App_Code 中,我不知道这在处理异常时是否会有所不同。
    • @OsamaMortada:你当然可以抛出ApplicationException。也许是SecurityException?在这种情况下,您甚至可能想要创建一个自定义异常并抛出它。类似于NotLoggedInException。自定义异常的好处在于您也可以为它定义自己的字段。因此,在您检查该异常类型的Application_Error 中,您可以轻松地从这些自定义字段中获取数据。
    • 谢谢大卫,我认为 SecurityException 更好,因为我注意到 ApplicationException 总是在 HttpException 中抛出,我必须从内部异常中获取它!我不知道为什么应用程序异常总是在 HttpException 中扭曲?我也会尝试自定义例外,谢谢大卫:)
    • 虽然例如成员资格提供者或 WIF 用于身份验证,但经过身份验证的用户由框架存储在当前线程上下文中,并且可以从 System.Threading.Thread.CurrentPrincipal 或在 Web 应用程序中检索,也可以从 @987654332 @.
    【解决方案2】:

    上述技术是否适合处理这种情况?

    没有

    如何以及在哪里可以在统一的地方检查会话是否存在?

    您可以将会话相关逻辑添加到基本页面中 这个讨论会对你有帮助ASP.net "BasePage" class ideas


    您可以在所有 aspx 页面中继承 BasePage。以下是示例示例

    public class BaseClass : System.Web.UI.Page
    {
        public String UserName
        {
            get
            {
                if (HttpContext.Current.Session["UserName"] == null)
                    Response.Redirect("Login.aspx");
                return Convert.ToString(HttpContext.Current.Session["UserName"]);
            }
        }
    

    我还几乎在每个页面中都使用 Employee's Session 来获取一些 有关已登录员工或其权限级别等的详细信息..

        public String FirstName
        {
           get
           {
               if (UserName == null)
                  return String.Empty;
               return Convert.ToString(HttpContext.Current.Session["FirstName"]);
           }
        }
    }
    

    【讨论】:

    • 感谢您的回答,我会阅读更多关于基类的信息,我认为它会很有用。
    猜你喜欢
    • 2017-05-05
    • 1970-01-01
    • 2014-02-26
    • 2013-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    相关资源
    最近更新 更多