相同类型的Object的InvalidCastException - 自定义控件加载

Ari*_*tos 28 c# asp.net compiler-construction user-controls dynamic-compilation

我有一个非常有线的错误,我的一个自定义控件似乎是创建两个编译文件,当我尝试动态加载它LoadControl()只是失败因为无法将一个转换为另一个 - 即使它们完全相同.我写的消息看到的一切都是一样的,只是改变了编译过的dll.

System.Web.HttpUnhandledException (0x80004005):     
 Exception of type 'System.Web.HttpUnhandledException' was thrown. --->             
    System.InvalidCastException:
[A]ASP.Modules_OneProduct_MedioumImage cannot be cast to
[B]ASP.Modules_OneProduct_MedioumImage.         

   Type A originates from 'App_Web_kg4bazz1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default'
    at location 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\80ed7513\10eb08d9\App_Web_kg4bazz1.dll'.          

   Type B originates from 'App_Web_oneproduct_mediumimage.ascx.d1003923.4xoxco7b, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' 
in the context 'Default'    
    at location 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\80ed7513\10eb08d9\App_Web_oneproduct_mediumimage.ascx.d1003923.4xoxco7b.dll'.
Run Code Online (Sandbox Code Playgroud)

代码

在我完全按照MSDN上的内容编写后,这就是现在的代码:

foreach (int OneProductID in TheProductIdArrays)
{
    // here is the throw.
    ASP.Modules_OneProduct_MedioumImage OneProduct = 
        (ASP.Modules_OneProduct_MedioumImage)LoadControl(@"~/mod/OneProduct_MediumImage.ascx");

    // do some work with 
    //OneProduct
}
Run Code Online (Sandbox Code Playgroud)

以前我没有加载控件ASP.但是在出现此错误并寻找解决方案之后,我严格遵循MSDN上的内容.无论我做什么,这个bug仍然在这里.

我也尝试了这两种方法,每种方法都在一起,并且一起(再次失败)

<%@ Register src="~/mod/OneProduct_MediumImage.ascx" tagname="OneProduct_MediumImage" tagprefix="uc1" %>
<%@ Reference Control="~/mod/OneProduct_MediumImage.ascx" %>
Run Code Online (Sandbox Code Playgroud)

配置

我的web.config,我尝试使用maxBatchSize20,100,1000,也有optimizeCompilations真或假,但错误再次出现.

<compilation debug="false" defaultLanguage="C#" batch="true"
maxBatchSize="800" batchTimeout="10800" optimizeCompilations="false"
targetFramework="4.0">
Run Code Online (Sandbox Code Playgroud)

现在一些细节

  • 错误是随机的,在某些编译中出现,在其他一些不是.
  • 这个项目是一个很大的项目,页面上有很多人在每一分钟都要求看到的东西,但也会在内部没有人的情况下出现.
  • 运行在64bit dot.net 4,Intergrated
  • 作为网络花园运行,但也测试和单独一个池(并得到相同的问题)
  • 整个项目的会议结束.
  • 这些页面是从2007年开始运行的,但是这个问题出现在上个月,遗憾的是我无法找到启动的位置和方式,或触发它的原因是因为我有些日子才看到它.
  • 仅出现一个自定义控件加载,即具有大量调用的加载.
  • 我已经改变了4次代码做了很小的改动,或者做了很大的改变,仍然存在.
  • 我尝试过optimizeCompilations真假,同样的问题.
  • 我也尝试通过停止网络,删除所有临时文件,重新打开,然后再次.
  • 当应用程序当时开始仅锁定一个编译时,我尝试在global.asax上放置一个互斥锁,但这也失败了.
  • 从有效的那一刻开始,一切都很好,但如果没有,工作就不会自动纠正.
  • 我加载此自定义控件的代码是存在的,并在代码上的多个位置,在不同的页面上调用.
  • 具有类似负载的其他自定义控件没有任何问题.
  • 此自定义控件禁用ViewState.
  • 我也尝试重新定位一些代码,用微优化更改完整的函数调用,不再失败.
  • 在开发计算机上工作正常.我batch="true"放在web.config上,然后就会出现错误.
  • 没有像这样的其他问题,就像我们无法解决的错误一样.系统运行了几天,池根本没有回收,内存稳定,还有更多免费使用.该程序现已运行多年,但我们几乎每天都会更新.
  • 在相同的核心代码下运行多个站点(类似于stackexchange)并且都具有相同的随机问题.
  • AutoEventWireup为false
  • 它出现,并在其他自定义控件上,我加载相同的方式.

当我出现此错误时,我现在所做的是解决方法:我只是通过一个小的更改强制项目重新编译,并且错误消失,直到下一次更新.

我有一个错误,尝试解决最后一个树周,找出原因.我几乎尝试了任何我能做到的事情,但都失败了,而且这个bug又出现了.所以我在这里发帖也许有些人可以帮我解决这个问题.

最后一句:这个bug很疯狂,自定义控件是一样的,我对它做任何事情我只是动态加载它并且繁荣,编译器有两个不同的时间由于某种原因只有他知道 - 随机.

更新1

我能够在开发者机器上重现该错误.在那里我发现包含这个自定义控件的两个dll模块有不同.

一个是一组4个自定义控件.另一个模块是单独的自定义控件.

解决方法

在尝试修复此错误的树周后,我最终发现当编译器批量编译目录并在同一个dll中捆绑许多不同的自定义控件时会出现此错误.因此,当我尝试单独加载它时会抛出此异常.

所以我将有问题的自定义控件单独移动到另一个目录中,似乎我现在就避免使用它.

更新2

即使我将一些文件移动到另一个目录后再次出现.是随机的,无法找到与其触发的明确联系.

更新3

因为我们发现这里的主要问题是批处理compile(batch="true"),它在同一个dll上编译许多自定义控件,一种说法是编译器不这样做的方法是maxBatchGeneratedFileSize参数.我使用它的值为100,问题再次出现,现在我将它降低到40并测试它.

maxBatchGeneratedFileSize="40"
Run Code Online (Sandbox Code Playgroud)

Dav*_*bbo 11

当您打开批处理并在目录级别具有某种形式的循环引用时,可能会发生这种情况.

请看这个答案,看看在这种情况下'循环引用'的确切含义,因为含义非常微妙.

如果您设法打破循环(例如,通过将用户控件移动到其他位置),您将不会遇到此问题.

更新1

我认为从理论上讲,这只能由一个周期引起,但有时它们很难被发现.

我会给你一个替代解决方案,我觉得它会起作用并且很容易尝试(即使它有点像黑客).在给您提供问题的用户控件中,在指令中添加以下属性:

<%@ Control Language="C#" [...] CompilerOptions="/define:dummy1" %>
Run Code Online (Sandbox Code Playgroud)

如果你看到这个与其他一些控件,你可以添加相同的东西,但与dummy2,dummy3等...

这将具有不对这一个用户控件进行批处理的效果,因为它具有与其他用户控件不同的编译需求.从技术上讲,你可以添加任何一段C#命令行CompilerOptions,但虚拟/define是最简单,最无害的.

但与全局关闭批处理不同,性能影响将是最小的,因为只有非常小的页面子集不会被批处理.

顺便说一句,毋庸置疑,你所看到的是ASP.NET中的一个错误,而且这个bug已经有10年多了!也许在某些时候应该得到解决:)