2011-03-04 75 views
1

我们正在使用动态编译的ASP.NET网站项目,并且最近移至SQL Server支持的会话状态并开始出现奇怪的错误。我已经找出了造成这种情况的原因,但我不知道解决问题的最佳方法。ASP.NET网站+ SQL备份会话

重现步骤在本地主机(启用SQL会话):

  • 放置在AppCode定义的对象,可以说这是一个DanObject到会话中。

    Session [“x”] = new DanObject();

  • (会话被序列化到数据库)

  • 修改应用程序代码的东西,导致网站重新编译的下一个请求
  • 请给访问会话的任何页面的请求

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

发生什么事是每次AppCode被编译时,它会进入一个随机命名的程序集。当我的会话第一次序列化时,AppCode碰巧被命名为AppCode_123。当我修改我的应用程序时,AppCode现在是AppCode_456。然而,存储在我的数据库中的Session有一个在AppCode_123中定义的对象。当会话尝试对DanObject进行二进制反序列化时,它会因为无法找到AppCode_123而炸毁。

我能解决这个问题的最简单方法是什么?
*请不要说切换到Web应用程序 - 我们的代码库是巨大的,这是不可行的,在这一点上:)

回答

0

问题是我们在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个Web服务器共享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的自定义实现服务器支持会话。

1

使用明确的命名空间周围DanObject

+1

+1:到目前为止,对于一个巨大的应用程序最简单的修复。当然,我建议不要在会话中存储完整的对象,但听起来这个项目已经是一个性能噩梦,所以在这一点上它可能并不重要。 – NotMe 2011-03-04 17:35:51

+0

@Chris Lively就是这样,我已经开始写作关于进入单独的图书馆,看看你在序列化的东西,但是我认为我现在会回答KISS,回答是明智的。 – dove 2011-03-04 17:37:21

+0

这没有奏效。我认为BinarySerializer正在使用AssemblyQualifiedName,它包括AppCode – dan 2011-03-04 18:17:13

0

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

三最简单的(和最好的一个)解决方案:
不要把物品放入会话。如果您需要一些属性,那是一回事,请将这些属性存储为常规字符串。

<slight_rant> 

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

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

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

</slight_rant> 
+0

上的随机名称,我们不直接在服务器上编辑应用程序代码。我们在负载平衡器上有多个服务器,并且我们希望能够在每天中午推送代码而无需占用整个站点...因此,我们将服务器移出轮换,将新代码推送到它,然后将其放回在旋转。问题是从AppCode序列化的对象爆炸。 – dan 2011-03-04 18:54:04