【问题标题】:ASP.NET Web Site + SQL Backed SessionASP.NET 网站 + SQL 支持的会话
【发布时间】:2011-06-16 13:33:40
【问题描述】:

我们正在使用具有动态编译功能的 ASP.NET 网站项目,并且最近转移到 SQL Server 支持的会话状态并开始出现奇怪的错误。我已经弄清楚是什么原因造成的,但我不知道解决它的最佳方法。

在 localhost 上重现的步骤(启用 sql 会话):

  • 在 AppCode 中定义一个对象,假设它是一个DanObject 到会话中。

    Session["x"] = new DanObject();

  • (Session被序列化到数据库)

  • 修改应用代码中的某些内容,导致网站在下一次请求时重新编译
  • 向访问会话的任何页面发出请求

错误是“无法找到程序集 'App_SubCode_CS.rmdbqb81, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'。”

发生的情况是每次编译 AppCode 时,它​​都会进入一个随机命名的程序集。当我的 Session 第一次被序列化时,AppCode 恰好被命名为 AppCode_123。当我修改我的应用程序时,AppCode 现在是 AppCode_456。但是,存储在我的数据库中的 Session 在 AppCode_123 中定义了一个对象。当 Session 尝试对 DanObject 进行二进制反序列化时,它会因为找不到 AppCode_123 而崩溃。

解决此问题的最简单方法是什么?
*请不要说切换到 Web 应用程序——我们的代码库很大,目前不可行:)

【问题讨论】:

    标签: asp.net session session-state web-site-project


    【解决方案1】:

    在 DanObject 周围使用显式命名空间

    【讨论】:

    • +1:目前为止最简单的大型应用修复。当然,我建议不要在会话中存储完整的对象,但听起来这个项目已经是一场性能噩梦,所以现在可能无关紧要。
    • @Chris Lively 确切地说,我已经开始写关于移动到单独的库并查看您正在序列化的内容,但我想我现在会接吻,回答明智。
    • 这不起作用。我认为 BinarySerializer 使用的是 AssemblyQualifiedName,其中包括 AppCode 上的随机名称
    【解决方案2】:

    好的,第二个最简单的解决方案:
    移动这个类的代码,而不是一个单独的程序集库。这样,当序列化程序看到该类时,它将有一个已知的好名称可以使用。当然,这消除了您直接对 app_code 目录进行编辑的能力......无论如何您都不应该这样做。

    第三种最简单(也是最好的)解决方案:
    不要将对象放入会话中。如果您需要几个属性,那是一回事,将这些属性存储为常规字符串。

    <slight_rant>
    

    说真的,将完整的对象放入会话中并不是它的目的。

    请在此处查看我的回答 (Sessions and storing objects),了解有关您不想这样做的原因的更多信息。

    最后一点:这个问题似乎只是一个问题,因为你们正在坚持会话并直接更改网络服务器上的代码。别那样做。在本地进行更改(并对其进行测试),然后预编译和部署您的站点,最后在部署后使会话无效。按照标准化的发布时间表执行此操作,以便每个人都知道停机时间。

    </slight_rant>
    

    【讨论】:

    • 我们不会直接在服务器上编辑应用代码。我们在负载均衡器上有多个服务器,我们希望能够在中午推送代码而不会关闭整个站点......所以我们将服务器从轮换中取出,将新代码推送到它,然后将其放回在旋转。问题是从 AppCode 序列化的对象爆炸了。
    【解决方案3】:

    问题是我们在App_Code 中有不同的文件夹,用于不同的代码语言。这就是为什么在错误消息中,它说“App_SubCode_CS...”而不是“App_Code...”,因为特定类来自 CS 代码文件夹(用于 c# 代码)。这些代码文件夹(在 web.config 中定义)中的每一个都被编译成自己的程序集。

    通常当您没有多个代码文件夹 AppCode 时,ASP.NET 能够序列化和反序列化在不同时间或不同服务器上编译的对象,因为程序集名称(“AppCode.randomstring”)与类名一起存储在序列化输出中。在反序列化时,框架在程序集 + 类名称上调用 System.Type.GetType(),并且该函数有一个特殊情况来处理以 App_Code 开头的程序集名称,如果它没有找到名称完全相同的程序集,但它确实找到一个以 App_Code 开头的,它使用该程序集来加载类。

    当您在App_Code 中有语言文件夹时,生成的程序集命名为:App_SubCode_FOLDERNAME.randomstring,框架似乎无法处理这种情况。因此,如果您有 2 个网络服务器共享一个支持 Sql 的会话,则类 Foo 在服务器 A 上编译为 "App_SubCode_FN.random1, Foo",在服务器 B 上编译为 "App_SubCode_FN.random2, Foo"。如果用户在其会话中从服务器 A 获取 Foo,然后他的下一个请求转到服务器 B,服务器 B 将无法反序列化 Foo,因为它找不到名为 "App_SubCode_FN.random1" 的程序集。

    可以通过摆脱旧的 VB 代码(允许将应用程序代码编译成 .NET 更适合使用的单个程序集)或编写自定义 SerializationBinder + Sql Server 的自定义实现来解决问题支持的会话。

    【讨论】:

      猜你喜欢
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      • 2010-12-22
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2011-03-31
      相关资源
      最近更新 更多