ASP.NET MVC 5 发布预编译问题

ASP.NET MVC 5 publish precompile problems

我过去曾使用网络发布工具发布我的 MVC 5 应用程序,而没有进行预编译。为了减少每个页面的初始加载时间,我修改了发布设置,如下所示,以便在发布过程中预编译应用程序。突然间,我习惯的极其可靠的出版变成了一场噩梦。

我试过重新启动 visual studio、清理解决方案并重新构建、预览与不预览发布前的更改、创建全新的发布配置文件以及一次又一次地摆弄高级预编译设置。通常在使用它大约 30 分钟后,我可以生成 .precompiled 文件并成功发布,但是我无法确定当时是什么原因导致它正常工作。下次我去发布 而不更改任何设置 时,它将再次停止工作。使用 VS2015 或 VS2017RC 时会出现此问题。

任何人都可以帮我指出正确的方向吗?我已经在这方面投入了很多时间,现在感觉自己在兜圈子。

谢谢!

编辑 我仔细查看了构建输出,发现对 aspnet_compiler.exe 的调用是使用以下参数执行的:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v / -p C:\Users\steve\Source\Dashboard\master\src\Agility.Web\obj\Staging\AspnetCompileMerge\Source -d C:\Users\steve\Source\Dashboard\master\src\Agility.Web\obj\Staging\AspnetCompileMerge\TempBuildDir

当我直接从命令行 运行 此命令时,TempBuildDir\bin 中没有生成 .compiled 个文件。

Visual Studio使用ASP.NET编译工具ASP.NET合并工具,它们是Aspnet_compiler.exeAspnet_merge.exe 来编译 ASP.NET 应用程序。

幕后VS使用这2个工具来编译web应用程序项目。或者,您可以从命令行调用这 2 个工具。

您可以通过导航到此目录找到这 2 个文件:%WINDIR%\Microsoft.NET\Framework\v4.0.30319(或您正在使用的任何框架版本)。 您可以使用这些工具来编译 ASP.NET 应用程序。 要了解有关这两个工具的所有选项的更多信息,请阅读以下链接:Aspnet_compiler.exe and Aspnet_merge.exe

我对解决问题的建议:

  • 重启Visual Studio
  • 清理重建您的解决方案
  • 您应该只输入没有.dll 的程序集名称(in your example Dashboard.Precompiled.dll should be just Dashboard.Precompiled)
  • (你可以考虑)重启你的机器

请阅读此 link 上有关高级预编译设置的更多信息,我也将选项粘贴在这里:

允许预编译站点可更新 - 此设置对应于 aspnet_compiler.exe 命令的 –u 选项。 如果您 select 此选项,页面和用户控件(.aspx、.ascx 和 .master 文件)将被复制 as-is 到目标文件夹,并且可以作为文本文件更新而无需重新编译项目。否则,页面和用户控件的 HTML 标记将被删除并编译到程序集输出中。

发出调试信息 - 此设置对应于 aspnet_compiler.exe 命令的 -d 选项。

不合并 - 此设置不运行 aspnet_merge.exe 并且不使用aspnet_compiler.exe 命令的-fixednames 选项。

不合并。为每个页面和控件创建一个单独的程序集 - 此设置不会运行 aspnet_merge.exe。相反,它使用 aspnet_compiler.exe 命令的 -fixednames 选项。 如果您想对已部署的网站进行精细更新,则此选项很有用。但是,使用 -fixednames 选项编译会禁用编译器的批处理优化,并可能导致大型网站的编译时间更长。

将所有输出合并到一个程序集 - 此设置等同于 aspnet_merge.exe 命令的 -o assemblyname 选项。

视为库组件(删除 App_Code.compiled 文件) - 此设置对应于 aspnet_merge.exe 命令的 -r 选项。 选择此选项可以将项目的 App_Code.dll 程序集添加到另一个网站的 Bin 文件夹中,而不会与其他网站中的 App_Code.dll 程序集发生冲突。这对于构建 .ascx 控件库很有用

将每个单独的文件夹输出合并到其自己的程序集 - 此设置对应于 aspnet_merge.exe 命令的 -prefix prefixname 选项。 此选项使您能够在文件夹级别更新您的网站,而不是更新整个应用程序。您可以使用“可选程序集前缀”框指定所有生成的程序集名称的前缀 pre-pended。例如,如果您指定前缀 MyCompany,名称将变为 MyCompany.SubfolderName.

将所有页面和控制输出合并到单个程序集 - 此设置对应于 aspnet_merge.exe 命令的 –w assemblyname 选项。 此选项使您能够独立于更新其他代码来更新 UI 元素。 App_Code、App_WebReferences 等特殊文件夹分别编译成单独的程序集。在程序集名称框中指定目标程序集名称。

请尝试以下步骤。

1.将解决方案配置更改为发布模式。

2. 确保 web.config 正在发布。

3. 检查 web.config 文件的属性,查看构建操作是否设置为 None,如果是,则将其设置为内容。并再次 运行 命令。

4. 仅将 DashBoard.Precomiled.dll 更改为 DashBoard.Precomiled。

5. 同时选中“视为库组件”复选框。

有关选项的更多详细信息,请访问 ASP.NET Compilation Tool (Aspnet_compiler.exe)

谢谢

我想确切地找出两者之间的区别:

  • "Do not merge" 和 "Do not merge. Create a separate assembly for each page and control."
    • 听起来它们做的是一样的,有什么区别?
  • "Merge all outputs to a single assembly" 和 "Merge all pages and control outputs to a single assembly"
    • 同样,这些听起来像是同一件事(当您没有 App_Code 文件夹时)。

而且我想知道为什么 "Allow precompiled site to be updatable" 在检查时似乎没有做任何事情(即我认为它会将页面预编译为它们自己的 assembly/assemblies 而 发出原始的可编辑*.aspx.ascx.master文件。

所以,今天我坐下来创建了一个电子表格,运行 使用 ASP.NET WebForms *.csproj 应用程序的每个不同的发布配置文件预编译设置 - 我还想看看什么是最慢的与最快的输出。

背景:

  • 我的 ASP.NET 项目目标是 .NET Framework 4.7.2
  • 这不是 "Website project"。
  • 原始 C# *.cs 文件未发布到生产 Web 服务器。
  • 这是一个使用 *.aspx*.ascx*.master*.ashxGlobal.asax 的 WebForms 项目。它不是使用 Razor *.cshtml 或 WebForms *.aspx 视图引擎的 MVC 项目。
  • 它不使用 App_Code 文件夹(因此 "Treat as library component" 选项无效)。

调查结果:

重要提示:

  • 这些发现仅在您使用 "traditional" ASP.NET Web Forms Web 应用程序项目时适用。这些不适用于 ASP.NET 网站项目(您没有 *.csproj 文件)、ASP.NET MVC(非核心)项目或 ASP.NET 核心项目。
  • 我使用术语 "Page files" 作为 shorthand 表示 *.aspx*.ascx*.master*.asmx*.ashx 文件,但 不是 Global.asax.
  • 我使用术语 "Built normally" 来指代在 Visual Studio 中执行 "Build > Rebuild project",您可以在 %projectdir%\bin 目录中看到输出。这与执行发布构建(将首先执行正常构建,然后将输出复制到另一个目录以 运行 发布 MSBuild 步骤)
  • 进行比较

以下是我对每个选项的结果的发现:

  • "Precompile during publishing"(在发布设置中window)

    • 如果您没有 App_Code 文件夹并且您想要发布可编辑的 *.aspx/*.ascx/`*.master 文件则没有选中此框的性能原因
      • 这是因为检查此功能时,但是"Allow precompiled site to be updatable" is unablected ,它将仅将您的Global.asax file(不是您的Global.asax.cs) ,无论如何都会编译)。
      • 即您的 *.aspx*.ascx*.master*.ashx 文件将 不会 预编译为程序集,它们仍然需要在网络服务器上按需编译。
      • 但它仍会预编译它们以检查 *.aspx*.ascx*.master、[=51= 中的编译器错误和损坏的 <% @ 行] 和 *.ashx 个文件。
  • "Allow precompiled site to be updatable"

    • 如果检查了您的 *.aspx*.ascx*.master*.ashx 文件,将 不会 预编译为程序集,它们仍然需要在网络服务器上按需编译。
      • 我最初认为它会将这些文件预编译为程序集 (DLL) 并另外发布原始 *.aspx 文件以在服务器上进行编辑,并且只有在它们发生更改时才重新编译它们 - 但我错了.
  • 发出调试信息

    • 这会为预编译过程生成的每个新程序集生成 *.pdb 个文件。它 不会 影响正常构建应用程序时已经存在的任何 *.pdb 文件。
    • 我认为这应该始终启用 - PDB 文件对于快速调查运行时间问题是必不可少的,并且它们不会对最终发布大小增加太多。
  • 不合并

    • 当您没有 App_Code 文件夹并且选中 "Allow precompiled site to be updatable" 时,"Do not merge" 只会将 Global.asax 完全预编译为 [=62] =].不会将其他 DLL 文件添加到最终发布输出中。

    • 当取消选中"Allow precompiled site to be updatable"时,所有页面文件(在上面的"Important notes"下定义)将被编译成新的DLL文件App_Web_xxxxxxxx.dll 10 人一组 类.

      • 我看不出它是如何决定将文件分组为它使用的 10 个文件的模式 - 有时它们按字母顺序排列,其他时候它是任意的。
  • 不合并。为每个页面和控件创建一个单独的程序集。

    • 这与上面相同,除了每个程序集不是以 10 个 页面文件 (或 类)为一组,它是 1-页面文件-每个程序集。
    • 当未选中 "Allow precompiled site to be updatable" 时,这也是最慢的发布版本之一。
    • 这种方法的唯一优点是,如果您想单独替换服务器上每个页面的预编译 *.dll - 但我认为这不是一个好主意,因为它经常会中断 - 最好替换一次所有文件。仅当您使用 56K 连接并且一次只能上传少于 100KB 时才执行此操作 - 这太愚蠢了。
  • 将所有输出合并到一个程序集中

    • 真的 compile/merge 所有 页面文件 Global.asax (App_global.asax.dll)单个 DLL 文件。
  • 视为库组件

    • 此选项对我的项目影响为零,无论是选中还是未选中(因为我的项目没有 App_Code 文件夹)。
  • 将每个单独的文件夹输出合并到它自己的程序集中

    • 这会为项目中包含页面文件的每个文件系统目录生成中间 DLL,然后将它们合并到每个文件夹的单个 DLL 中。
    • 此选项导致发布构建时间第二长。
    • 我想不出您今天需要使用此功能的充分理由 - 除非您的项目有数千个 页面文件 分布在数十个文件夹和想要进行手动增量更新。 (即这不是您在 CI/CD 过程中使用的选项)。
  • 将所有页面和控制输出合并到一个程序集中

    • 如果您有 App_Code 文件夹:
      • 然后 App_Code(以及其他 "Special folders",如 App_GlobalResourcesApp_WebReferences)的内容将从您的 页面预编译到这个单独的程序集中文件 程序集。这将包含Global.asax(编译为App_global.asax.dll)。
    • 如果您没有 App_Code 文件夹,则此选项会产生与 "Merge all outputs to a single assembly" 非常相似的输出,除了最终输出将 Global.asax 预编译为其自己的程序集(App_global.asax.dll).
      • 此选项导致所有选项中最长的发布构建时间 - 在我的案例中实际收益为零。
      • 因此,如果您没有 App_Code 文件夹,则没有理由选择此选项。

重述:

勾选"Allow precompiled site to be updatable"和勾选"Do not merge"时:

*.aspx
*.ascx
*.ashx
*.asmx
*.master

    * Compiled only for error-checking.
    * Not compiled to an assembly DLL in the `bin\` folder.

Global.asax

    * Compiled to `App_global.asax.dll`

App_Code

    * Compiled to `App_Code.dll`

不勾选"Allow precompiled site to be updatable"而勾选"Do not merge"时:

*.aspx
*.ascx
*.ashx
*.asmx
*.master

    * Compiled to `App_Web_abcdefghij.dll` in groups of 10-per-DLL

Global.asax

    * Compiled to `App_global.asax.dll`

App_Code

    * Compiled to `App_Code.dll`

不勾选"Allow precompiled site to be updatable",勾选"Merge each individual folder output to its own assembly"时:

*.aspx
*.ascx
*.ashx
*.asmx
*.master

    * Each file compiled to its own `App_Web_OriginalFileName.abcdefghij.dll` file.

Global.asax

    * Compiled to `App_global.asax.dll`

App_Code

    * Compiled to `App_Code.dll`

不勾选"Allow precompiled site to be updatable"而勾选"Merge all outputs to a single assembly (named 'Everything')"时:

*.aspx
*.ascx
*.ashx
*.asmx
*.master

    * Compiled and merged into the single Everything.dll

Global.asax

    * Compiled and merged into the single Everything.dll

App_Code

    * Compiled and merged into the single Everything.dll

不勾选"Allow precompiled site to be updatable",勾选"Merge each individual folder output to its own assembly"时:

*.aspx
*.ascx
*.ashx
*.asmx
*.master

    * Compiled into an assembly for each folder.

Global.asax

    * Compiled to `App_global.asax.dll` (separate from the assembly for the *.aspx files in the root directory)

App_Code

    * Compiled and merged into `App_Code.dll`

勾选"Merge all pages and control outputs to a single assembly (named 'PagesAndControls')"时:

*.aspx
*.ascx
*.ashx
*.asmx
*.master

    * Compiled into PagesAndControls.dll

Global.asax

    * Compiled to `App_global.asax.dll` (separate from PagesAndControls.dll)

App_Code

    * Compiled and merged into `App_Code.dll`

结论:

如果您不需要编辑 *.aspx/*.ascx,/*.master 文件,并且您没有 App_Code文件夹,然后选择这些设置以获得最佳效果:

[ ] Allow precompiled site to be updatable
[X] Emit debug information
[X] Merge all outputs to a single assembly 
[ ] Treat as library component

方法论:

  • 所有构建都在使用 Release。
  • 使用了 "Folder" 发布配置文件。
    • 目标是同一磁盘卷(PCI-Express Optane 驱动器)上的文件夹。
    • 文件夹在每次 运行 后被清除。
  • 每个测试之间的唯一变化 运行 是更改
  • 中的参数
  • git 确认在每次构建和发布之前对源文件和项目文件进行零更改。
  • 我运行一个shell脚本完全清除binobj目录之间的每个运行,所以web-application项目完全在 运行 秒之间重建,而不仅仅是发布)。
  • 我使用了一个秒表程序来记录我单击“发布”按钮的确切时间,但是当我看到“发布”操作已完成时被键盘按下手动停止。

结果:

(我的电子表格的屏幕截图)