9

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

  • 我对“将所有输出合并到单个程序集”的理解意味着我的所有.cshtml页面将一起编译成Dashboard.Precompiled.dll,然后部署到 IIS。情况并非如此 - 当我能够发布工作时,它会为我的项目.complied中的每个.cshtml文件创建一个文件并且不执行任何合并。

  • 现在的主要问题.compiled是 仅在某些时候生成。当我查看obj\Debug\AspnetCompileMerge\TempBuildDir\bin目录时,没有.compiled文件,也没有Dashboard.Precompiled.dll.

我尝试重新启动 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

当我直接从命令行运行此命令时,不会.compiledTempBuildDir\bin.

在此处输入图像描述

4

3 回答 3

11

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

  • “不要合并”和“不要合并。为每个页面和控件创建一个单独的程序集。”
    • 听起来这些都做同样的事情,有什么区别?
  • “将所有输出合并到一个程序集”和“将所有页面和控制输出合并到一个程序集”
    • 同样,这些听起来像是同一件事(当您没有App_Code文件夹时)。

而且我想找出为什么“允许预编译的站点可更新”在检查时似乎没有做任何事情(即我认为它会将页面预编译为他们自己的程序集/程序集,同时还发出原始的可编辑文件.*.aspx.ascx.master

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

背景:

  • 我的 ASP.NET 项目面向 .NET Framework 4.7.2
  • 它不是一个“网站项目”。
  • 原始 C#*.cs文件不会发布到生产网络服务器。
  • 它是一个使用*.aspx*.ascx*.master*.ashx的WebForms 项目Global.asax。它不是使用 Razor*.cshtml或 WebForms *.aspx视图引擎的 MVC 项目)。
  • 它不使用App_Code文件夹(因此“视为库组件”选项无效)。

发现:

重要说明

  • 这些发现仅适用于使用“传统”ASP.NET Web 窗体 Web 应用程序项目的情况。这些不适用于 ASP.NET 网站项目(没有*.csproj文件)、ASP.NET MVC(非核心)项目或 ASP.NET Core 项目。
  • 我使用术语“页面文件”作为*.aspx*.ascx*.master*.asmx*.ashxfiles 的简写,但不是 Global.asax.
  • 我使用术语“正常构建”来指代在 Visual Studio 中执行“构建 > 重建项目”,您可以在其中看到%projectdir%\bin目录中的输出。这与执行 Publish Build 相比(它将首先执行正常构建,然后将输出复制到另一个目录以运行 Publish MSBuild 步骤)

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

  • “发布期间预编译”(在发布设置窗口中)

    • 如果您没有App_Code文件夹并且想要发布可编辑的*.aspx/ *.ascx/`*.master 文件,则没有性能理由来选中此框
      • 这是因为当检查此功能时,“允许预编译的站点可更新”是未选中的,则只会预先编译您的Global.asax文件(而不是您的文件Global.asax.cs)。
      • 即您的*.aspx,*.ascx*.master文件*.ashx不会预编译为程序集,它们仍然需要在 Web 服务器上按需编译。
      • 但它仍会预编译它们以检查<% @您的*.aspx*.ascx、和文件*.master中的编译器错误和断行。*.asax*.ashx
  • “允许预编译站点可更新”

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

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

    • 如果您没有App_Code文件夹并选中“允许预编译的站点可更新”,则“不合并”只会完全预编译Global.asaxApp_global.asax.dll. 不会将其他 DLL 文件添加到最终发布输出中。

    • 当“允许预编译的站点可更新”未选中时,所有页面文件(在上面的“重要说明”下定义)将被编译成App_Web_xxxxxxxx.dll10 个类为一组的新 DLL 文件。

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

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

    • 确实将所有页面文件 Global.asax( App_global.asax.dll) 编译/合并为单个 DLL 文件。
  • 视为库组件

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

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

    • 如果你有一个App_Code文件夹:
      • 然后App_Code(和其他“特殊文件夹”,如App_GlobalResources, App_WebReferences)的内容将从您的页面文件程序集预编译到这个单独的程序集。这将包括Global.asax(编译为App_global.asax.dll)。
    • 如果您没有App_Code文件夹,则此选项会产生与“将所有输出合并到单个程序集”非常相似的输出,但最终输出将预编译Global.asax为其自己的程序集 ( App_global.asax.dll)。
      • 此选项导致所有选项的发布构建时间最长 - 在我的情况下,实际收益为零。
      • 因此,如果您没有App_Code文件夹,则没有理由选择此选项。

重述:

当检查“允许预编译的站点可以更新”并检查“不要合并”时:

*.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`

当未选中“允许预编译站点可更新”并选中“不合并”时:

*.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`

当未选中“允许预编译站点可更新”并且选中“将每个单独的文件夹输出合并到其自己的程序集”时:

*.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`

当未选中“允许预编译站点可更新”并且选中“将所有输出合并到单个程序集(名为 '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

当未选中“允许预编译站点可更新”并且选中“将每个单独的文件夹输出合并到其自己的程序集”时:

*.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`

选中“将所有页面和控件输出合并到单个程序集(名为 '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。
  • 使用了“文件夹”发布配置文件。
    • 目标是同一磁盘卷(PCI-Express Optane 驱动器)上的文件夹。
    • 每次运行后都会清除该文件夹。
  • 每次测试运行之间的唯一变化是更改
  • git在每次构建和发布之前确认源文件和项目文件的零更改。
  • 我运行了一个 shell 脚本,它在每次运行之间完全清除binobj目录,因此 Web 应用程序项目在运行之间完全重建,而不仅仅是 Publish)。
  • 我使用了一个秒表程序,它记录了我单击“发布”按钮的确切时间,但是当我看到“发布”操作完成时,它被键盘按下手动停止。

结果:

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

预编译输入选项和观察输出的 Excel 电子表格屏幕截图

于 2019-08-04T19:07:07.467 回答
7

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

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

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

我对解决问题的建议:

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

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

允许预编译站点可更新- 此设置对应于 aspnet_compiler.exe 命令的 -u 选项。如果选择此选项,页面和用户控件(.aspx、.ascx 和 .master 文件)将按原样复制到目标文件夹,并且可以作为文本文件进行更新,而无需重新编译项目。否则,页面和用户控件的 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 选项。此选项使您能够在文件夹级别更新您的网站,而不是更新整个应用程序。您可以使用可选程序集前缀框来指定一个前缀,该前缀将添加到所有生成的程序集名称之前。例如,如果您指定前缀 MyCompany,则名称将变为 MyCompany.SubfolderName。

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

于 2017-02-09T21:40:25.680 回答
4

请尝试以下步骤。

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

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

3.检查 web.config 文件的属性,看看 Build Action 是否设置为 None,如果是,请将其设置为 Content。并再次运行该命令。

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

5.也选中视为库组件复选框。

有关选项的更多详细信息,请访问ASP.NET 编译工具 (Aspnet_compiler.exe)

谢谢

于 2017-02-10T09:19:45.647 回答