无法将预编译的合并webapp部署到Azure

时间:2014-12-18 19:47:12

标签: asp.net azure msbuild azure-web-sites kudu

我正在尝试将ASP.NET Web应用程序部署到Azure。它是混合Web窗体,MVC和WebAPI,并且有一些TON的aspx / ascx文件,因此它们确实需要预先编译,或者每次部署都会使网站暂时缓慢。

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

请注意:

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

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

  • 不允许预编译网站使用udpatable
  • 不要发出调试信息
  • 将所有页面和控件输出合并到单个程序集= 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标记,但我不清楚如何通过.deployment文件让MSBuild添加它,或者即使该应用程序确实是偶数抛出错误。

我可以通过Visual Studio部署,但我真的喜欢利用SCM集成,所以我可以推送到我的prod分支并放手。有什么建议吗?

2 个答案:

答案 0 :(得分:3)

我在https://github.com/projectkudu/kudu/issues/1341回复,但是在这里复制我的答案,万一有人来到这里......

回过头来看,我们发现aspnet_compiler.exe在Azure网站中无法正常工作,因为它处理了配置文件文件夹。我们做了一个更改,但是让我们开始了:通过将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网站托管环境的改进。因此,我们将尝试摆脱这种黑客并进行完整的测试通过,以确保它不会导致任何重大的回归。如果一切顺利,我们可以将其投入生产,这将启用这些方案。

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

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

答案 1 :(得分:1)

注意:This GitHub issue on projectkudu最终会使此解决方案过时,但与此同时,该问题将作为Backlog提交,现在可以正常使用。

谢谢大卫艾伯。通过这些信息,我能够在短期内引导我的构建工作。

首先,我使用https://{WEBSITE_NAME}.scm.azurewebsites.net/DebugConsole处提供的诊断控制台从A​​zure实例下载了aspnet_compiler.exe,并将其添加到我自己的存储库中。通过这种方式,32/64-bit等之间没有任何区别,我将其重命名为我的存储库中的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" />

然后我在它下面添加了这个,这基本上是从AspNetPreCompile窃取了C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Transform\Microsoft.Web.Publishing.AspNetCompileMerge.targets的MSBuild目标定义,其中一些属性设置内容靠近它的顶部(因为原来的)无论如何,任务都会为我们做到这一点。)只需记下(重命名的)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>

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