使用 ClientBuildManager.CompileFile 进行原地编译

13

我正在开发一个网站,希望使用就地编译来加快首次加载速度。我想使用ClientBuildManager.CompileFile方法进行就地编译,以便我能够控制编译过程。由于种种原因,这是编译该网站的理想方式。

为什么IIS在“Temporary ASP.NET Files”下构建到不同的子目录中?

当我使用专门构建的exe文件通过ClientBuildManager.CompileFile方法逐个文件对网站进行编译时,输出结果会保存到“Temporary ASP.NET Files”下的一个子目录中。但是,当稍后访问该网站时,IIS会将控件重新构建到“Temporary ASP.NET Files”下的另一个子目录中,使得之前的就地编译变得毫无用处。

注意:在“Temporary ASP.NET Files”下进行就地编译时创建的程序集将保留(仍存在)

注意:就地编译程序集文件夹和IIS生成的程序集文件夹都在同一个“Temporary ASP.NET Files”目录下。

示例:

  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ba591b9\[就地编译文件夹名称]
  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\2ba591b9\[网站生成的IIS程序集]\

ClientBuildManager.CompileFile配置

var buildParameter = new ClientBuildManagerParameter
   {
      PrecompilationFlags = PrecompilationFlags.Default,
   };
var clientBuildManager = new ClientBuildManager(
   RootVirtualPath, RootPhysicalPath, null, buildParameter);
...
clientBuildManager.CompileFile(relativeVirtualPath, callback);

其中RootVirtualPath对于默认网站来说只是一个空字符串。 RootPhysicalPath指向网站在磁盘上的位置。 relativeVirtualPath的格式为"~/myFile.aspx"。回调函数用于跟踪进度。


我猜测,即使您调用PrecompileApplication而不是CompileFile,使用此代码,它们也不会最终位于同一个文件夹中。我已经有一段时间没有查看过这些内容,因此可能需要深入挖掘源代码。 - David Ebbo
2个回答

12

我认为您所看到的实际上与使用 CompileFilePrecompileApplication 无关。也就是说,如果您执行相同的操作但调用 PrecompileApplication(),您仍将得到文件夹不匹配的错误。

请注意,从技术上讲,您没有正确创建CBM对象。正确的调用方式是依靠IIS信息来定位文件。方法如下:

  • 对于appVirtualDir传递类似于/LM/W3SVC/7/ROOT/的内容
  • 对于appPhysicalSourceDir传递null

请注意,“7”只是一个示例。要获取正确的编号:

  • 运行inetmgr
  • 进入站点的高级设置
  • 找到站点ID。这就是您要在/LM/W3SVC/ID/ROOT/中使用的编号

我正在记录此解释,因为不幸的是,即使以这种方式,我仍然无法使文件夹匹配。很可能这种情况在ASP.NET中是有问题的(过去它可以工作!)。

另一种可能性是在服务器端处理。例如:

  • 在您的网站中包含一个页面,您将用它来触发有选择的预编译。
  • 在其中,为每个页面(或用户控件等)调用BuildManager.GetCompiledType("~/myfile.aspx")等类似调用以进行预编译。
  • 当您想要触发自定义预编译时,只需请求该页面即可。

当然,还有一种简单的方法是提前请求您想要编译的页面以加热您的网站。


谢谢!有参考的工单号码吗?也许我今天可以问一些负责这段代码的人。 - David Ebbo
1
你是正确的。将"/ LM / W3SVC / [SITE ID] / ROOT /"作为appVirtualDir的IIS路径添加,然后将null作为appPhysicalSourceDir传递即可解决问题。请注意必须传递null以使其正常工作。谢谢。你一直都有答案。我想我第一次没有仔细阅读它。 - Sam
我认为我引起困惑的地方是当我说我尝试过那个方法,但它实际上对我没有起作用。我不确定为什么它没有起作用,但我很高兴它对你有用。这个方法也适用于微软支持技术员(Bret),所以我可能做错了什么 :) - David Ebbo
1
这个方法适用于重新编译已更改的视图吗?我在我的MVC ASP.NET应用程序中使用插件架构,因为视图在请求时编译,当我删除并重新安装插件视图时,会出现缺少程序集/命名空间异常。我正在尝试强制服务器重新编译新插件目录中的视图。有什么建议吗?谢谢 - sambomartin
1
顺便说一下,当我使用 aspnet_compiler.exe -m 遇到同样的问题时,我不得不将路径指定为 /LM/W3SVC/<ID>/ROOT不要加斜杠。否则,编译输出将被放置在错误的目录中。 - Jeff Sharp
显示剩余4条评论

3

Sam,答案是David Ebbo的回答和你的原始代码之间的结合。

var buildParameter = new ClientBuildManagerParameter
   {
      PrecompilationFlags = PrecompilationFlags.Default,
   };
var clientBuildManager = new ClientBuildManager(
   RootVirtualPath, RootPhysicalPath, null, buildParameter);
...
clientBuildManager.CompileFile(relativeVirtualPath, callback);

如果你按照David Ebbo所说的做法,在构造ClientBuildManager时使用以下RootVirtualPath:

/LM/W3SVC/7/ROOT/

然后,你需要将RootPhysicalPath设为null。

这样就可以消除其余的问题,并且应该构建到与IIS查找的目录相同的目录中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接