【问题标题】:ASP.NET: Multiple Session objects in a single applicationASP.NET:单个应用程序中的多个 Session 对象
【发布时间】:2009-04-06 16:20:11
【问题描述】:

我有一个在 Web 服务器根目录运行的 ASP.NET Web 应用程序,它通过使用 URL 重定向提供多个(相似的)网站。举一个现实世界的例子:

http://webshopserver/company1/ProductList.aspx -> http://webshopserver/ProductList.aspx?showProductsFrom=company1
http://webshopserver/company2/ProductList.aspx -> http://webshopserver/ProductList.aspx?showProductsFrom=company2
...

这很好用;唯一的问题是,显然,所有这些不同的商店共享相同的会话对象(因为 InProc 会话管理器将会话对象存储在 AppDomain 中)。我希望 company1 和 company2 的商店具有不同的会话对象,例如,如果用户在同一浏览器窗口的不同选项卡中打开 company1 和 company2 的商店,则放入 company1 购物车的商品会赢'不会出现在 company2 的购物车中。

有一些我不喜欢的明显方法来解决这个问题:

  • 创建我自己的 Session 对象,它将所有内容封装到一个 HashMap 中,然后将其存储在“真实”会话中:这会破坏所有使用会话对象的现有代码。
  • 使用像 http://company1.webshopserver/ 这样的 URL 和通配符 DNS 记录,因为会话 ID cookie 与域相关:这很难看(因为现实世界中相当于“webshopserver”的时间已经够长了)。
  • 编写我自己的自定义会话提供程序:这有点像重新发明轮子。
  • 为每个公司创建一个单独的 IIS 应用程序:行不通,因为应该可以通过 http://webshopserver/CreateYourOwnWebshop.aspx 之类的方式创建新公司,之后无需任何人工(服务器管理员)干预。

我正在考虑更多的解决方案:

因此,任何有关如何实现其中一个点(或完全不同的解决方案)的信息都会有所帮助。

【问题讨论】:

  • 对不起,我错过了单独的 IIS 应用程序上的禁止使用。这是一个自托管的应用程序还是在您只能访问控制面板的共享环境中运行?
  • 没问题,无论如何感谢您的回答。它(目前)是一个自托管的应用程序。

标签: asp.net session


【解决方案1】:

难道最简单的解决方案不是使用基于公司的动态键更新对依赖于公司的 Session 对象的引用吗?

例如……

Session["IsTest"]

变成

Session[createSessionKey(CompanyID, "IsTest")]

createSessionKey 可能通过 Company 和 Key 的简单串联生成相应的密钥

这将通过生成的密钥访问会话来区分两家或更多公司。

按照上面的示例,company1 将通过键“company1_IsTest”访问“IsTest”会话变量,company2 将通过键“company2_IsTest”访问“相同”的“IsTest”会话变量。

希望您没有像 Session("IsTest") 之类的东西在您的代码库中乱扔垃圾,因为这会使重构您的代码变得非常痛苦。

通常我将我的 Session 变量抽象为一个强类型的类。然后我的会话管理包含在一个地方。

如果所有 Session 变量都是公司特定的,那么使用具有基 Page 类并覆盖 Session 属性的想法是一个不错的方法。尽管如果您可以确定特定的 Session 键是通用 Session 变量还是公司特定的,那么它仍然可以使用。

【讨论】:

  • 虽然这是问题中排除的方法之一(创建会话包装器),但我会将其标记为答案,因为这就是我最终使用的方法。
【解决方案2】:

我建议编写自己的会话包装器。这是另一个问题中Martin 的一个很好的例子:

How to access session variables from any class in ASP.NET?

【讨论】:

    【解决方案3】:

    根据您在 Session 中添加和检索项目的方式(并且可能取决于您是否从公共基本页面派生页面),您可能能够执行包装会话的自定义对象在不破坏所有代码的情况下(如您的第一个选项中所述,您将会话包装器实现为由站点键入的哈希映射)。如果您创建一个自定义对象并将其公开为基本页面级别的“会话”,它将优先于您从 Page 类继承的会话对象。然后,您的自定义对象可以覆盖索引器,并根据当前 http 上下文的请求 url 确定在 hashmap 中存储该对象的位置。

    如果您不是从一个通用的基本页面派生的,那么这有点过时了,因为您必须为所有页面实现一个基本页面来派生,或者向每个页面添加代码以获取对你的对象。只是和想法......

    【讨论】:

      【解决方案4】:

      创建您自己的 Session 包装器或自定义 Session Provider 将是正确的答案。但是,您可以通过移动现有会话数据来破解它,因为用户去另一家公司,HttpModule 与 PostAcquireRequestState 挂钩。

      基本上,将此 ProductsFromCompany 与之前的 ProductsFromCompany 进行比较。如果它们不同,请将所有现有 Session 值移动到 Dictionary<string, object>(或在它们前面添加公司 ID)并将此 ProductsFromCompany 保存的 Dictionary<string, object> 恢复到 Session。

      类似:

      void PostAcquireRequestState(object sender, EventArgs e) {
         if (Session["ProductsFromCompany"] != Request["ProductsFromCompany"]) {
            var lastCompanySession = new Dictionary<string, object>(Session.Count);
            var sessionKeys = Session.Keys;
            foreach (string key in sessionKeys) {
               if (key == "CompanyState" || key == "ProductsFromCompany") {
                  continue;
               }
               lastCompanySession[key] = Session[key];
               Session.Remove(key);
            }
            Session["CompanyState"].Add(Session["ProductsFromCompany"], lastCompanySession);
      
            var thisCompanySession = Session["CompanyState"][Request["ProductsFromCompany"]];
            foreach (string key in thisCompanySession.Keys) {
               Session[key] = thisCompanySession[key];
            }
            Session["CompanyState"].Remove(Request["ProductsFromCompany"]);
      
            Session["ProductsFromCompany"] = Request["ProductsFromCompany"];
         }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-11
        • 1970-01-01
        • 2019-06-12
        • 1970-01-01
        • 2011-08-30
        相关资源
        最近更新 更多