【问题标题】:Can't deploy precompiled, merged webapp to Azure无法将预编译、合并的 webapp 部署到 Azure
【发布时间】:2014-12-18 19:47:12
【问题描述】:

我正在尝试将 ASP.NET Web 应用程序部署到 Azure。它是 Web 表单、MVC 和 WebAPI 的混合体,并且有大量的 aspx/ascx 文件,因此它们确实需要进行预编译,否则每次部署都会使网站延迟一段时间。

我正在尝试通过 kudu 与 GitHub 的 SCM 集成进行部署,使用预编译的视图,全部合并到一个程序集中。

注意:

  • 在禁用预编译的情况下,Deploy 可以正常工作。
  • 在 Visual Studio 中部署工作正常
  • 如果我从 Azure 日志中复制 msbuild 命令、替换相关路径并在我的 Windows 8.1 计算机上本地运行,则构建工作正常。

我已将高级预编译设置设置为:

  • 不允许预编译的网站可更新
  • 不发出调试信息
  • 将所有页面和控件输出合并到一个程序集 = AppViews.dll

这是 Azure 的 .deployment 文件

[config]
project = WebSite/WebSite.csproj
SCM_BUILD_ARGS=/p:Configuration=Release;PublishProfile=azure-prod /v:n

您注意到我将详细程度 /v 发送到“正常”以获取额外的诊断信息。

这是我在部署日志尾部获得的信息:

AspNetPreCompile:
  D:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v \ -p D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\Source -c D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir 
GenerateAssemblyInfoFromExistingAssembleInfo:
  Creating directory "obj\Release\AssemblyInfo".
  D:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe /out:obj\Release\AssemblyInfo\AssemblyInfo.dll /target:library Properties\AssemblyInfo.cs
AspNetMerge:
  Running aspnet_merge.exe.
  D:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\aspnet_merge.exe D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir -w AppViews.dll -copyattrs obj\Release\AssemblyInfo\AssemblyInfo.dll -a  
aspnet_merge : error 1003: The directory 'D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir' does not exist. [D:\home\site\repository\WebSite\WebSite.csproj]
Done Building Project "D:\home\site\repository\WebSite\WebSite.csproj" (Build;pipelinePreDeployCopyAllFilesToOneFolder target(s)) -- FAILED.

Build FAILED.

它看起来像 aspnet_compiler.exe 运行,但没有做它应该做的,这就是为什么 TempBuildDir 目录(应该是编译器的输出)对于 AspNetMerge 目标没有及时存在。与我的系统相比,该目录确实存在,包含标记 aspx/ascx/etc。文件、静态内容、PrecompiledApp.config 文件以及 bin 目录中的一大堆东西。

aspnet_compiler.exe 有一个 -errorstack 标志,但我不清楚如何让 MSBuild 仅通过 .deployment 文件添加它,或者即使该应用程序真的抛出错误。

我可以通过 Visual Studio 进行部署,但我真的想利用 SCM 集成,这样我就可以推送到我的 prod 分支并放手。有什么建议吗?

【问题讨论】:

  • aspnet_compiler 被 Azure 网站上的 stub exe 替换。您可能想在此处提交问题 - github.com/projectkudu/kudu - 以便部署团队跟踪它并找出解决方案。
  • @Pranav 你有任何文件证明它是一个存根 exe 吗?我从 Kudu 服务 URL (sitename.scm.azurewebsites.net) 下载了 exe,并使用 dotTrace 检查,看起来基本相同。我什至尝试将我的本地副本添加到我的存储库并使用自定义 MSBuild 目标来更改使用我自己的路径,但无济于事。

标签: asp.net azure msbuild azure-web-app-service kudu


【解决方案1】:

我在https://github.com/projectkudu/kudu/issues/1341 上回复了,但是在这里复制我的答案以防有人登陆这里...

回到过去,我们发现 aspnet_compiler.exe 无法在 Azure 网站中运行,因为它处理配置文件文件夹的方式。我们当时做了一个改动,这有点像 hack,但让我们继续前进:我们通过将 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\aspnet_compiler.exe 指向我们自己的虚拟 exe (D:\Program Files (x86)\aspnet_compiler\KuduAspNetCompiler.exe) 将其变成了无操作。

但现在尝试一下,它现在似乎可以正常工作,这可能要归功于 Azure 网站托管环境的改进。因此,我们将尝试摆脱这种黑客攻击并进行完整的测试通过,以确保它不会导致任何重大回归。如果一切顺利,我们可以将其投入生产,这应该会启用这些场景。

在短期内,您可以通过构建脚本来解决此问题:

  • 将 aspnet_compiler.exe 从 D:\Windows\Microsoft.NET\Framework\v4.0.30319 复制到您自己的站点文件中,但使用不同的名称(例如 aspnet_compiler2.exe
  • 说服 msbuild 使用那个

【讨论】:

    【解决方案2】:

    注意:This GitHub issue on projectkudu 最终将使该解决方案过时,但与此同时,该问题被归档为待办事项,并且现在有效。

    谢谢,谢谢大卫·埃博。有了这些信息,我能够引导我的构建在短期内工作。

    首先,我使用https://{WEBSITE_NAME}.scm.azurewebsites.net/DebugConsole 提供的诊断控制台从 Azure 实例下载了 aspnet_compiler.exe,并将其添加到我自己的存储库中。这样就不用怀疑 32/64 位等之间的任何区别。我在我的存储库中将其重命名为 azure_aspnet_compiler.exe

    其次,AspNetCompiler 任务不提供更改工具名称的选项。它是硬编码的,但作为一个虚拟属性,所以它是可覆盖的。所以我必须创建自己的任务类,并将其打包到自己的程序集中,我以发布模式构建并包含在我的存储库中。

    public class AzureAspNetCompiler : Microsoft.Build.Tasks.AspNetCompiler
    {
        private string _toolName = "aspnet_compiler.exe";
    
        protected override string ToolName
        {
            get { return _toolName; }
        }
    
        public string CustomToolName // Because ToolName cannot have a setter
        {
            get { return _toolName; }
            set { _toolName = value; }
        }
    }
    

    接下来我需要替换 MSBuild 中的 AspNetPreCompile 任务,但我不知道如何直接执行此操作。但是那个任务并没有任何事情,所以为什么不直接在它之后运行呢?

    我将此添加到我的Website.csproj 文件的顶部以导入包含AzureAspNetCompiler 类的DLL。请注意,该路径是相对于我正在编辑的Website.csproj 文件的。

    <UsingTask TaskName="AzureBuildTargets.AzureAspNetCompiler"
               AssemblyFile="..\DeploymentTools\AzureBuildTargets.dll" />
    

    然后我在它的正下方添加了这个,这基本上是从C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Transform\Microsoft.Web.Publishing.AspNetCompileMerge.targets 窃取了AspNetPreCompile 的MSBuild 目标定义,并省略了它顶部附近的一些属性设置内容(因为原始任务会这样做无论如何对我们来说。)只需注意(重命名)AzureAspNetCompiler 元素底部的 ToolPathCustomToolName 值。

    <PropertyGroup>
            <!--Relative to solution root apparently-->
            <LocalRepoDeploymentTools>.\DeploymentTools</LocalRepoDeploymentTools>
            <AzureAspnetCompilerPath>$([System.IO.Path]::GetFullPath($(LocalRepoDeploymentTools)))</AzureAspnetCompilerPath>
    </PropertyGroup>
    
    <Target Name="NoReallyAspNetPreCompile" AfterTargets="AspNetPreCompile">
    
    <AzureAspNetCompiler
      PhysicalPath="$(_PreAspnetCompileMergeSingleTargetFolderFullPath)"
      TargetPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)"
      VirtualPath="$(_AspNetCompilerVirtualPath)"
      Force="$(_AspNetCompilerForce)"
      Debug="$(DebugSymbols)"
      Updateable="$(EnableUpdateable)"
      KeyFile="$(_AspNetCompileMergeKeyFile)"
      KeyContainer="$(_AspNetCompileMergeKeyContainer)"
      DelaySign="$(DelaySign)"
      AllowPartiallyTrustedCallers="$(AllowPartiallyTrustedCallers)"
      FixedNames="$(_AspNetCompilerFixedNames)"
      Clean="$(Clean)"
      MetabasePath="$(_AspNetCompilerMetabasePath)"
      ToolPath="$(AzureAspnetCompilerPath)"
      CustomToolName="azure_aspnet_compiler.exe"
        />
    
    <!--
        Removing APP_DATA is done here so that the output groups reflect the fact that App_data is
        not present
        -->
    <RemoveDir Condition="'$(DeleteAppDataFolder)' == 'true' And Exists('$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data')"
               Directories="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data" />
    
    
    <CollectFilesinFolder Condition="'$(UseMerge)' != 'true'"
      RootPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)" >
      <Output TaskParameter="Result" ItemName="_AspnetCompileMergePrecompiledOutputNoMetadata" />
    </CollectFilesinFolder>
    
    <ItemGroup Condition="'$(UseMerge)' != 'true'">
      <FileWrites Include="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\**"/>
    </ItemGroup>
    

    有了这个,一切都会按照我的预期进行。

    【讨论】:

      猜你喜欢
      • 2013-02-26
      • 2020-01-05
      • 1970-01-01
      • 2019-02-21
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多