IIS オート スタート設定による ASP.NET Web アプリケーションの初回実行時のパフォーマンス向上の罠
IIS オート スタート設定による ASP.NET Web アプリケーションの初回実行時のパフォーマンス向上 - THE TRUTH IS OUT THERE - Site Home - MSDN Blogsをやってて罠に嵌りまくった腹いせエントリ。
すいません言い過ぎました。
● Windows Azure クラウドサービスで IIS/ASP.NET オートスタートを使う
続いて、この ASP.NET アプリケーションのオートスタートの設定を Windows Azure クラウド サービスを使った Web アプリケーションで有効にする方法をご紹介します。
クラウド サービスでも Web ロールにリモートデスクトップ (RDP) 接続して、上記と同じ手順で設定は可能です。しかしながら、スケールアップなどの際に、増やしたインスタンス一つ一つに RDP 接続して設定を行うのは現実的ではありません。オートスケールなどでインスタンスが自動で増減する場合はなおさらです。このような場合に、Windows Azure クラウドサービスでは、スタートアップタスクと、ロールの初期化時のイベントハンドラを利用することで、上記のオートスタートの設定を行うことができます。
IIS オート スタート設定による ASP.NET Web アプリケーションの初回実行時のパフォーマンス向上 - THE TRUTH IS OUT THERE - Site Home - MSDN Blogs
1. スタートアップタスクで Application Initialization モジュールを有効化する
まず、ASP.NET Web アプリケーションのプロジェクトに Startup.cmd ファイルを追加して、プロパティで [出力ディレクトリにコピー] を [常にコピーする] に設定します。
このStartup.cmdはUTF-8じゃなくてANSIじゃないとダメ。
VisualStudioでやってるとこれ忘れてクソハマる。超注意。
そして、Windows Azure クラウドサービス プロジェクトにある ServiceDefinition.csdef ファイルを開いて、下記の記述(太字部分)を追加します。
<ServiceDefinition ...> <WebRole name="WebAppPreload" vmsize="Small"> <Runtime executionContext="elevated"></Runtime> <Startup> <Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple" /> </Startup>
Runtime要素はWebRoleの最初に無いとAzureEmulatorでビシバシ落ちた。
IIS 8.0 Application Initialization module in a Windows Azure Web Role
この順番にしてる。
何でダメなのかまでは調べてない。
2. アプリケーション プール開始モードと Web サイトのプリロード機能の有効化
続いて、applicationHost.config へ行うアプリケーションプールの開始モードと Web サイトのプリロードの有効化ですが、下記のようなクラスを Web アプリケーションプロジェクトに追加し、Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint クラスの Run メソッドをオーバーライドして、その中でプログラムコードを通して設定します。
using Microsoft.Web.Administration; using Microsoft.WindowsAzure.ServiceRuntime; namespace WebApplication1 { public class WebRole : RoleEntryPoint { public override void Run() { using (var serverManager = new ServerManager()) { var mainSite = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"]; var mainApplication = mainSite.Applications["/"]; mainApplication["preloadEnabled"] = true; var mainApplicationPool = serverManager.ApplicationPools[mainApplication.ApplicationPoolName]; mainApplicationPool["startMode"] = "AlwaysRunning"; serverManager.CommitChanges(); } base.Run(); } public override bool OnStart() { return base.OnStart(); } } }
これEmulator Express環境下でがっつり落ちた。
問題はここ
var mainSite = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"]; var mainApplication = mainSite.Applications["/"];
どうやらserverManagerが正しくEmulatorExpressのインスタンスを指していないようで、Sitesには"Default Web Site"だけが登録されてた。おそらくIISそのもののデータを引いてるくさい。
その為にmainSite.Applications["/"]がぬるぽで死ぬ。
なのでローカルではここを迂回するようにした。
var mainSite = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"]; if (mainSite!=null){ var mainApplication = mainSite.Applications["/"]; : }
というログ。