カスタム UI モジュール ~ IIS マネージャの拡張方法
IIS Manager は拡張可能な管理画面です。この資料では IIS7 の IIS マネージャ (IIS Manager) を拡張し、 ワーカープロセスの PID (プロセス ID) を表示する機能を追加するサンプルを通して、 管理コンソールの拡張方法を示します。
この資料で示すように、UI を持つ管理画面を拡張して自分の使いやすいようにすることも簡単です。 サーバーのホスティング環境では、なかなか IIS マネージャをそのまま使うということは無いかもしれませんが、 自前でサーバーを立てるときには、管理画面もカスタマイズして管理しやすい環境を作ることが出来ます。
あなたのアプリケーションにあった管理機能を IIS マネージャと一体化させれば、 集中管理型のコントロールパネルのように利用でき、非常に便利になるでしょう。
IIS マネージャの拡張例
はじめに完成図をご覧ください。
この資料で作成する拡張 UI モジュールを登録すると次のようになります。
IIS Manager に Worker Process というエントリが追加されています。
Worker Process というアイコンがあり、これを開くと現在実行中のワーカープロセスの情報が表示されています。 ワーカープロセスのプロセス ID (PID) などは、デバッグのときにも必要になります。
拡張方法
ソースコード
ではさっそくコードを示します。詳細な説明はまた後で時間のあるときに書きます。
以下のコードを DadoTest.cs として保存します。
// // DadoTest.cs // // Author: Dado-san // http://keicode.com/ // using System; using Microsoft.Web.Administration; using Microsoft.Web.Management.Server; using Microsoft.Web.Management.Client; using Microsoft.Web.Management.Client.Win32; using System.Windows.Forms; using System.Reflection; [assembly:AssemblyVersion("1.0.0.0")] namespace DadoIISTest { ///////////////////////////////////////////////////////////////////////// class AppInfoProvider : ModuleProvider { public override Type ServiceType { get { return null; } } public override ModuleDefinition GetModuleDefinition ( IManagementContext context ) { return new ModuleDefinition( Name, typeof( AppInfoModule ).AssemblyQualifiedName ); } public override bool SupportsScope (ManagementScope scope) { return true; } } ///////////////////////////////////////////////////////////////////////// public class AppInfoModule : Microsoft.Web.Management.Client.Module { protected override void Initialize ( IServiceProvider serviceProvider, ModuleInfo moduleInfo ) { base.Initialize ( serviceProvider, moduleInfo ); IControlPanel cp = (IControlPanel) GetService ( typeof ( IControlPanel ) ); ModulePageInfo mpi = new ModulePageInfo ( this, typeof ( AppInfoPage ), "Worker Process", "Displays worker process information currently running" ); cp.RegisterPage ( mpi ); } } ///////////////////////////////////////////////////////////////////////// public class AppInfoPage : ModulePage { System.Windows.Forms.ListView listView1; System.Windows.Forms.ColumnHeader chdrProcessId; System.Windows.Forms.ColumnHeader chdrAppPoolName; System.Windows.Forms.Timer timer1; System.Windows.Forms.ColumnHeader chdrProcessGuid; System.Windows.Forms.ColumnHeader chdrState; public AppInfoPage() { InitializeComponent(); ShowInitialInfo(); } protected void InitializeComponent() { this.listView1 = new System.Windows.Forms.ListView(); this.chdrAppPoolName = new System.Windows.Forms.ColumnHeader(); this.chdrProcessId = new System.Windows.Forms.ColumnHeader(); this.chdrProcessGuid = new System.Windows.Forms.ColumnHeader(); this.chdrState = new System.Windows.Forms.ColumnHeader(); this.timer1 = new System.Windows.Forms.Timer(); // // listView1 // this.listView1.Columns.AddRange( new System.Windows.Forms.ColumnHeader[] { this.chdrAppPoolName, this.chdrProcessId, this.chdrState, this.chdrProcessGuid} ); this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; this.listView1.Name = "listView1"; this.listView1.TabIndex = 0; this.listView1.View = System.Windows.Forms.View.Details; this.chdrAppPoolName.Text = "AppPoolName"; this.chdrAppPoolName.Width = 127; this.chdrProcessId.Text = "Process ID"; this.chdrProcessId.Width = 81; this.chdrProcessGuid.Text = "ProcessGuid"; this.chdrProcessGuid.Width = 218; this.chdrState.Text = "State"; // // timer1 // this.timer1.Interval = 5000; this.timer1.Enabled = true; this.timer1.Tick += new System.EventHandler( this.timer1_Tick ); // // Form1 // this.Controls.Add( this.listView1 ); } protected void AddEntry( string AppPoolName, int ProcessId, string ProcessGuid, WorkerProcessState State) { ListViewItem lvi = new ListViewItem( AppPoolName ); lvi.SubItems.Add( ProcessId.ToString() ); lvi.SubItems.Add( State.ToString() ); lvi.SubItems.Add( ProcessGuid ); listView1.Items.Add( lvi ); } public void EnumWorkerProcess() { ServerManager manager = new ServerManager(); if ( manager.WorkerProcesses.Count == 0 ) { ShowNoWorkerProcess (); return; } foreach ( WorkerProcess wp in manager.WorkerProcesses ) { AddEntry( wp.AppPoolName , wp.ProcessId , wp.ProcessGuid , wp.State ); } } private void timer1_Tick( object sender , EventArgs e ) { listView1.Items.Clear(); EnumWorkerProcess(); } protected void ShowInitialInfo () { ListViewItem lvi = new ListViewItem( "Initializing..." ); listView1.Items.Add( lvi ); } protected void ShowNoWorkerProcess () { ListViewItem lvi = new ListViewItem( "No Worker Process Running." ); listView1.Items.Add( lvi ); } } }
以下を makefile として保存します。
CSC = csc.exe TARGETNAME=DadoTest SOURCE_FILE=DadoTest.cs OUTDIR=.\chk all: "$(OUTDIR)\$(TARGETNAME).dll" clean: -del $(OUTDIR)\*.xml -del $(OUTDIR)\*.pdb cleanall:clean -del $(OUTDIR)\$(TARGETNAME).dll igac: @gacutil /i $(OUTDIR)\$(TARGETNAME).dll /nologo @gacutil /l $(TARGETNAME) /nologo ugac: @gacutil /u $(TARGETNAME) /nologo "$(OUTDIR)" : @if not exist "$(OUTDIR)" mkdir "$(OUTDIR)" CSC_OPT=\ /nologo\ /target:library\ /out:$(OUTDIR)\$(TARGETNAME).dll\ /doc:$(OUTDIR)\$(TARGETNAME).xml\ /debug+\ /debug:full\ /optimize-\ /warn:3\ /keyfile:mykey.snk REF=\ /r:C:\Windows\System32\inetsrv\Microsoft.Web.Management.dll\ /r:C:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll $(OUTDIR)\$(TARGETNAME).dll: "$(OUTDIR)" $(SOURCE_FILE) mykey.snk $(CSC) $(REF) $(CSC_OPT) $(SOURCE_FILE) mykey.snk: sn -k mykey.snk
ビルドと GAC への登録
nmake でビルドして、nmake igac でグローバルアセンブリキャッシュ (GAC) にアセンブリを登録します。
> nmake Microsoft (R) Program Maintenance Utility Version 9.00.30729.01 Copyright (C) Microsoft Corporation. All rights reserved. csc.exe /r:C:\Windows\System32\inetsrv\Microsoft.Web.Management.dll /r:C:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll /nologo /target:library /out:.\chk\DadoTest.dll /doc:.\chk \DadoTest.xml /debug+ /debug:full /optimize- /warn:3 /keyfile:mykey.snk DadoTest.cs > nmake igac Microsoft (R) Program Maintenance Utility Version 9.00.30729.01 Copyright (C) Microsoft Corporation. All rights reserved. Assembly successfully added to the cache The Global Assembly Cache contains the following assemblies: DadoTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9b769a7e5b9541cc, processorArchitecture=MSIL Number of items = 1 >
administration.config への登録
administration.config に次を追加します。これは %WINDIR%\System32\inetsrv\config にあります。
PublicKeyToken の値は GAC に登録した時のトークンを見てください。上記コマンド結果に表示されています。
moduleProviders 要素に以下を追加します。
<add name="DadoIISTest" type="DadoIISTest.AppInfoProvider, DadoTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=[PublicKeyToken]"/>
type は [名前空間].[クラス名], [アセンブリ名] の順番で記載します。
modules 要素に以下を追加します。
<add name="DadoIISTest"/>
以上で、IIS Manager にモジュールが追加されるはずです。
いかがでしょうか。たったこれだけのコードで IIS マネージャを拡張することが可能です。 IIS のサーバー環境を非常に快適に利用するためにも、どんどん良い拡張機能を開発するひとが出てくるといいですね。