ASP.NET:单个应用程序中的多个Session对象

时间:2009-04-06 16:20:11

标签: asp.net session

我有一个在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的购物车中的商品赢了不会出现在公司2的购物车中。

有一些明显的方法可以解决我不喜欢的问题:

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

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

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

4 个答案:

答案 0 :(得分:7)

最简单的解决方案是不是更新对基于公司的动态密钥公司依赖的Session对象的引用?

例如......

Session["IsTest"]

变为

Session[createSessionKey(CompanyID, "IsTest")]

其中createSessionKey可能通过Company和Key

的简单连接生成相应的键

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

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

希望你的代码库中没有像Session(“IsTest”)这样的东西,因为这会让你的代码重构变得非常痛苦。

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

如果所有Session变量都是特定于公司的,那么使用具有基页类并覆盖Session属性的想法是一个很好的方法。虽然如果您可以确定某个特定会话密钥是一般会话变量还是特定公司变量,那么它仍然可行。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

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

如果你不是从一个公共基页派生的,那么这种情况就会消失,因为那时你必须为所有页面实现一个基页,或者为每个页面添加代码以获得对它的引用。你的对象。只是想法......

答案 3 :(得分:1)

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

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

类似的东西:

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"];
   }
}