Server Error in '/' Application.
这是一件很奇怪的事情,因为我们的上线流程都会在内网部署一个Alpha版本,测试通过了才会正式的上限。其实本来也没有什么大问题,因为这并非一个关键业务,不上线也不会死人。可坏就坏在试图解决该问题的人光凭感觉和Google来解决问题,而没有经过自己的逻辑思考,最后导致整个服务器的所有IIS应用全部挂掉。他是怎么解决的呢?步骤如下:
在Google中搜索:“试图加载格式不正确的程序”,于是会出来一大堆的解决方案,大部分都讨论到平台类型的问题,甚至有的提到了32位和64位。我这里就节选当时的第一条搜索结果如下所示:
试图加载格式不正确的程序。 (异常来自HRESULT:0x8007000B) - 洛阳知道 ...
www.0379zd.com/news/show/36017.htm - 网页快照 - 类似结果
我们内网系统是32位的,而公网的这一台服务器却是64位的,会不会与此有关系呢?确实有关系。
嗯,很多人解决问题(包括改Bug)就是这样的——搜索之,然后看到确实有我指定的关键字,或者看起来差不多描述的是类似现象,而结论又说可以解决,于是乎就按照里面说的步骤开始执行。可是为什么会出现这个现象,对方遇到该问题的原因是否和你又是一回事,根本就没想过。更惨的是,有些东西看不懂,于是就不打算看懂而直接忽略了。如果真仔细看这个文章,一定会发现关键的线索的(后面再说)。这位仁兄估计没看懂,于是就继续看后面那几条搜索结果。然后看到如下一条,两眼发光——这不就是我遇到的现象么,简直一模一样:
试图加载格式不正确的程序--在64位OS下运行32位项目- kitleer的日志 ...
kitleer.blog.163.com/blog/static/9177857920102115045194/ - 网页快照
我这里进行部分的摘录,以便于大家阅读:
原因:程序集之间的通讯要么全是64位环境下的,要么全是32位环境下的。不能混编访问。不然会出现“试图加载格式不正确的程序”的错误。
……
B:建立的是“网站”:只需要修改IIS的配置就可以了。
i).“cscript %systemdrive%\inetpub\adminscripts\adsutil.vbs set w3svc/appPools/enable32bitapponwin64 1”
(enable32bitapponwin64为1代表可运行32位应用程序),该项可以通过 “命令行”执行一次。(此命令的作用是使IIS能够注册32位的.net FW)
ii).64位OP默认是在IIS下注册了64位的.net Framework的,因此还必须再注册一个32位的.net Framework
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727> aspnet_regiis.exe -i
太好了,连解决方案的步骤都有了,这么详细。这位仁兄就照此执行了,可是结果大大出乎所料——问题不仅没有解决,而且所有Web站点都挂了。为什么会挂呢?原因很简单,因为IIS里面的Web服务扩展禁用了32位的ASP.NET v4。因此即便执行了v4.0.30319\aspnet_regiis -i,也不可能启动该应用,而原本就在64位下执行得好好的所有应用也就突然都挂了。实际上这些ASP.NET都已经安装过,再执行一遍aspnet_regiis根本就不会产生任何改变。其实给出这种方案的文章,其作者要么不知甚解,要么就没有好好把问题的成因给描述清楚,实在有点误导的嫌疑。
实际上这个问题是如何造成的呢?如果你仔细读了第一篇文章,说的是PInvoke调用的目标Dll指定了32位平台,而自己写的程序编译时指定了64位平台。稍微思考一下,就会发现这是因为你这堆Dll/Exe当中,存在了目标平台不一致的情况。可是.NET不是号称跨平台、与CPU无关的吗?如果引用的Dll其它没有指定平台,也没有PInvoke,我们一般情况下用C#写的纯托管程序编译成exe之后,无论丢到32位还是64位的机器上,不都是应该能跑的吗?原因其实很简单:mscorlib.dll需要执行PInvoke(或者别的什么原因,没有仔细深究),这一个dll本身是和平台有关的。只不过不同的机器部署了不同的版本,甚至同时部署32位和64位的版本,于是你的平台无关的程序会自动选择并加载合适的mscorlib。因此,如果你编译的时候指定了目标平台,而最终却被强制选择在另一个目标平台下运行(如ASP.NET),就会出现“试图加载格式不正确的程序”这样的错误。
这个我们用Reflector一看就知道了:
上图中的mscorlib的平台就是x64的,而你编译出来的程序一般情况下应该是这样的:
也就是平台无关的。一般来说,只要你不使用非托管代码,不是用C++/CLR,并且不选择编译的目标平台类型,那都应该长上面那样。可想而知,如果你选择了x86的目标平台(嗯,我们这边产生该问题就是因为不小心编译成x86平台的),然后丢到一个使用64位的IIS/ASP.NET上面去运行,一定会出错——x86的目标代码试图加载x64的mscorlib自然是不行的。如果你和我们一样,只是因为手哆嗦了一下选了x86作为目标平台,而不是因为什么别的原因,那么解决的方法应该是将Target Platform改成Any再编译一次。而不是像这位仁兄一样,把IIS改成32位,这就本末倒置了。
动手之前,想想为什么。