我有一个 aspx 页面,它使用了 App Code 文件夹中的一个类中的方法,doSomething(int[] x)
. 我将函数定义更改为使用 IEnumerable 而不是数组:doSomething(IEnumerable<int> x)
。接下来,我预编译了网站,使用“允许网站可更新”,并发布了新的 App_Code.dll。现在,页面的预编译版本在运行时会出现服务器错误:“找不到方法”。
如果我还发布为页面生成的 DLL,“App_Web_[page].aspx.[random].dll”,它可以工作。所以看起来函数的签名以某种方式嵌入到编译页面中......?为什么会这样,在更改现有代码时有没有办法避免这个问题?
每当我更改公共类中的代码时,我都讨厌更新所有页面 DLL。
4 回答
编译页面时,它会查看所有方法签名并基本上将它们锁定。如果您更改正在调用的方法的签名,则页面将无法找到它,直到重新编译为止。
例如,假设您有一个像
public class Dog {
public void Walk(Int32 distance) {
/// blah blah
}
}
你在后面的页面代码中调用它:
protected void MyButtonClick(....) {
Dog d = new Dog();
d.Walk(3000);
}
当它编译下来时,页面将期望一个带有 Int32 签名的 walk 方法。
现在,假设我们将 Dog 类中的 walk 方法更改为:
public void Walk(Int16 distance) {
// blah blah
}
(是的,愚蠢的改变,但它突出了这个问题)。此时页面将无法找到采用 Int32 参数的 Walk 方法,因此会按原样崩溃。
只部署您认为需要的一个程序集似乎很好,但事实是代码中可能发生了任意数量的更改,因此这是一种非常糟糕的做法。
最好确保整个项目是一致的。甚至更大的网站也不需要那么长时间来部署。
当然,我认为使用网站项目本身就是不好的做法。将未编译的代码部署到服务器(非常糟糕),VS 搜索驱动器以更新项目中的引用,即使您已明确告诉它要使用哪个程序集(通常是意外的,永远不会好),将所有主要代码放在一个公共 app_code 文件夹中(限制)等。我可以在这里继续......
如果它是一个 Web 应用程序,那么每次更改服务器端代码时都需要重新编译 - 无论它是在单独的程序集中还是在 Web 应用程序的 App_Code 文件夹中。
只有网站(不是 Web 应用程序)允许您在不重新编译的情况下更改代码。
以下类型的更改可能会导致运行时异常:
更改方法的签名或属性的类型。如果受影响的成员被已编译的页面引用,则会引发异常。如果重新编译整个站点,某些签名更改不会导致编译或运行时错误。例如,.aspx 页面中的代码 Response.Write(ClassA.MethodA() 将编译并运行良好,无论 MethodA 返回 int 还是 short。但是如果 .aspx 页面已经编译并且您更改 MethodA 的返回类型从 int 到 short 无需重新编译,将抛出运行时异常,因为编译后的代码需要 int 签名。
来自http://msdn.microsoft.com/en-us/library/ms366723.aspx#sectionToggle5
您需要重新编译,因为您的页面已发布并输出到 bin 文件夹中的 dll。此 dll 正在寻找具有以下签名的方法:
doSomething(int[])
它已经不存在了。当您发布时,每次都更新所有内容。
我相信“可更新”标志允许您更新您的 aspx 代码(即标记),但代码隐藏文件将被编译掉。