3

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

我正在尝试通过 kudu 通过 SCM 与 GitHub 集成进行部署,并带有预编译的视图,所有这些都合并到一个程序集中。

注意:

  • 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 分支并放手。有什么建议么?

4

2 回答 2

3

我在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 使用那个
于 2014-12-23T01:49:46.793 回答
1

注意:projectkudu 上的这个 GitHub 问题最终会使这个解决方案过时,但与此同时,该问题被归档为 Backlog,并且现在可以正常工作。

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

首先,我使用可用的诊断控制台从 Azure 实例下载了 aspnet_compiler.exe,https://{WEBSITE_NAME}.scm.azurewebsites.net/DebugConsole并将其添加到我自己的存储库中。这样就没有任何关于 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; }
    }
}

接下来我需要替换AspNetPreCompileMSBuild 中的任务,但我不知道如何直接执行此操作。但是那个任务无论如何都没有任何事情,所以为什么不直接追它呢?

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

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

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

<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>

有了这个,一切都按我的预期工作。

于 2015-04-13T20:41:43.480 回答