しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET アプリケーションを Azure Web Apps にソース管理からデプロイする時にプリコンパイルさせる方法

Azure Web Apps に ASP.NET アプリケーションを GitHub などからデプロイする場合に、ビューのプリコンパイルを行いたいと思っていましたが、カスタムデプロイスクリプトを書くことで対応できたので紹介します。

やはり同じことを考える人は居たようですが、スクリプト例が見つかりませんでした。

aspnet_compiler.exe について色々書かれていましたが、現行の Web Apps にインストールされているもので問題なくプリコンパイル出来ました。

スクリプトの重要な部分というか、修正が必要な部分を順に解説していきます。

プリコンパイルを行う準備

最初にプリコンパイル前のビルド結果を一時的に格納させるためのディレクトリと、aspnet_compiler.exe のパスを用意しておきます。基本的に存在しないはずなので常に新しく作ります。

SET PRECOMPILE_TEMP=%temp%\___precompileTemp%random%
mkdir "%PRECOMPILE_TEMP%"

SET ASPNET_COMPILER_PATH=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe

これでランダムなディレクトリがデプロイごとに作成されます。

MSBuild の出力ディレクトリを変更

通常のデプロイスクリプトでは MSBuild の実行結果を DEPLOYMENT_TEMP に書き出すのですが、プリコンパイルするために今回作成した PRECOMPILE_TEMP に書き出すように変更します。

call :ExecuteCmd "%MSBUILD_PATH%" /p:_PackageTempDir="%PRECOMPILE_TEMP%" %SCM_BUILD_ARGS%

このコマンドは長いの不要な部分は削除しました。オリジナルのスクリプトから _PackageTempDir を指定してる部分を探して、そこを PRECOMPILE_TEMP に設定します。

aspnet_compiler でプリコンパイル

PRECOMPILE_TEMP に MSBuild でビルドされたアプリケーションのファイル一式が入っているので、それをソースにして DEPLOYMENT_TEMP にプリコンパイルした結果を出力します。

call :ExecuteCmd "%ASPNET_COMPILER_PATH%" -v / -p "%PRECOMPILE_TEMP%" -c "%DEPLOYMENT_TEMP%"

仮想ディレクトリを表す -v オプションの値は / のままで基本は良いと思います。DEPLOYMENT_TEMP に結果を出力すると、後は KuduSync が wwwroot に差分をコピーしてくれます。

プリコンパイルに使ったディレクトリを削除

追加したプリコンパイル用のディレクトリは Kudu によって自動的に削除されないので、スクリプトの最後の方で削除するようにしておきます。

IF EXIST "%PRECOMPILE_TEMP%" rd /s /q "%PRECOMPILE_TEMP%"

一応存在チェックを行ってから削除するようにします。

完成したスクリプト例

ここまで紹介したスクリプトを全て組み込んだ例を最後に張り付けておきます。

当然ですが、そのままコピペで使えるというわけではないです。これで処理の全体像を掴んでください。

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

SET PRECOMPILE_TEMP=%temp%\___precompileTemp%random%
mkdir "%PRECOMPILE_TEMP%"

SET ASPNET_COMPILER_PATH=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe

echo Handling .NET Web Application deployment.

:: 1. Restore NuGet packages
IF /I "AspNet.sln" NEQ "" (
  call :ExecuteCmd nuget restore "%DEPLOYMENT_SOURCE%\AspNet.sln"
  IF !ERRORLEVEL! NEQ 0 goto error
)

:: 2. Build to the temporary path
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\AspNet\AspNet.csproj" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="%PRECOMPILE_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release /p:SolutionDir="%DEPLOYMENT_SOURCE%\.\\" %SCM_BUILD_ARGS%
) ELSE (
  call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\AspNet\AspNet.csproj" /nologo /verbosity:m /t:Build /p:AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release /p:SolutionDir="%DEPLOYMENT_SOURCE%\.\\" %SCM_BUILD_ARGS%
)

IF !ERRORLEVEL! NEQ 0 goto error

:: 3. Precompile Razor
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%ASPNET_COMPILER_PATH%" -v / -p "%PRECOMPILE_TEMP%" -c "%DEPLOYMENT_TEMP%"
  IF !ERRORLEVEL! NEQ 0 goto error
)

:: 4. KuduSync
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
)

:: 5. Clean Precompile Dir
IF EXIST "%PRECOMPILE_TEMP%" rd /s /q "%PRECOMPILE_TEMP%"

デプロイスクリプトのひな形は Azure CLI を使うと簡単に作成できます。

Azure Web Apps (Websites) - Custom Deployment Scripts Generator

実際にこのスクリプトを組み込んだアプリケーションを Web Apps へ GitHub からデプロイすると、プリコンパイルが行われていることが確認できます。

f:id:shiba-yan:20150726235314p:plain

ビューをプリコンパイルしておくことで、アプリケーションの起動パフォーマンスを改善出来ます。

特に Azure Web Apps はアクセスが無いとインスタンスが落とされる関係上、仮想マシンなどに置いてあるアプリケーションよりも初回起動が多くなる傾向にあるので、プリコンパイルは有効な手段になります。