チュートリアル: IIS レポートの作成
公開日: 2008 年 5 月 21 日 (作業者: SinghGurpreet (英語))
更新日: 2008 年 5 月 28 日 (作業者: SinghGurpreet (英語))
はじめに
IIS レポートは、独自のレポート セットを作成して表示できる非常に強力なツールに進化しました。基本的なレポート セットが付属しているだけではなく、独自のレポートを作成し、プラグインとして IIS Reports プラットフォームで使用できます。このチュートリアルでは、基本的なレポートの作成方法について説明します。このレポートでは、aspx ページとヒット数を比較します。レポートの作成は、UI モジュールの作成と同じ手順に従います。単純な UI モジュールを作成する手順については、http://learn.iis.net/page.aspx/441/understanding-ui-extension-authoring/ を参照してください。
IIS レポートを作成する手順は、次の 2 つの部分に分けることができます。
- サーバー部分の作成
- クライアント部分の作成
サーバー部分の作成は、次の 2 つの部分で構成されます。
- ModuleProvider の作成
- ModuleService の作成
クライアント部分の作成は、次の 3 つの部分で構成されます。
- モジュールの作成
- レポート機能の作成
- レポートの作成
まず、サーバー部分を作成し、その後でクライアント部分を作成します。
モジュール プロバイダーの作成
この手順は、Inetmgr UI 用のモジュール プロバイダーの作成とよく似ています。
internal class TestModuleProvider : SimpleDelegatedModuleProvider {
public override ModuleDefinition GetModuleDefinition(IManagementContext context) {
return new ModuleDefinition(Name, "TestIisReportsClient.TestModule, " + AssemblyRef.TestReportClient);
}
public override Type ServiceType {
get {
return typeof(TestModuleService);
}
}
public override bool SupportsScope(ManagementScope scope) {
return (scope == ManagementScope.Server || scope == ManagementScope.Site);
}
public override string FriendlyName {
get {
return "IIS Reports Test";
}
}
}
TestModuleProvider は SimpleDelegatedModuleProvider から派生しています。これにより、このモジュールでは、サーバー管理者がサイト管理者にレポートを委任できます。
モジュール サービスの作成
TestModuleService は ModuleService から派生し、モジュール サービス プロキシや WMSVC で呼び出すことができる GetReport メソッドを公開します。内部的には、受け取った引数は ExecuteLogParserQuery に渡されます。ExecuteLogParserQuery は、LogParser を使用してクエリを解析し、出力を生成します。生成された ILogRecordSet は、オブジェクト配列にパックされ、クライアントに送信されます。TestModuleService は、GetFromClause() と GetCurrentSite() を使用して、解析する必要があるファイルのパスを取得します。
internal class TestModuleService : ModuleService {
[ModuleServiceMethod(PassThrough = true)]
public object[] GetReport(IDictionary arguments) {
object[] dataObject = null;
try {
dataObject = ExecuteLogParserQuery(arguments);
}
catch (Exception ex) {
RaiseException(ex.Message);
}
return dataObject;
}
private string GetQueryString(IDictionary arguments) {
string endDate = ((DateTime)arguments["ToDate"]).ToString("yyyy-MM-dd");
string startDate = ((DateTime)arguments["FromDate"]).ToString("yyyy-MM-dd");
string from = GetFromClause();
return "Select TOP 25 TO_LOWERCASE (cs-uri-query) as Site, Count(*) as hits from" + from
+ " where Site is not null and date BETWEEN TO_TIMESTAMP(\'" + startDate + "\',\'yyyy-MM-dd\') AND TO_TIMESTAMP(\'" + endDate + "\',\'yyyy-MM-dd\') group by Site order by Hits desc";
}
private object[] ExecuteLogParserQuery(IDictionary arguments) {
string query = GetQueryString(arguments);
object[] data = new object[2];
ILogRecordset rs = ExecuteQuery(query);
int columnCount = rs.getColumnCount();
object[] headers = new object[columnCount];
for (int i = 0; i < columnCount; i++) {
headers[i] = rs.getColumnName(i);
}
data[0] = headers;
// Add the results
ArrayList rows = new ArrayList();
while (!rs.atEnd()) {
object[] row = new object[columnCount];
ILogRecord record = rs.getRecord();
for (int i = 0; i < columnCount; i++) {
object value = record.getValue(i);
if (value is DBNull) {
value = String.Empty;
}
row[i] = value;
}
rs.moveNext();
rows.Add(row);
}
//Adding rows to object Array
data[1] = rows;
return data;
}
private ILogRecordset ExecuteQuery(string query) {
LogQueryClass logParser = new LogQueryClass();
ICOMIISW3CInputContext ctx = new COMIISW3CInputContextClassClass();
return logParser.Execute(query, ctx);
}
private string GetFromClause() {
Site site = GetCurrentSite();
if (site == null) {
ServerManager mgr = GetServerManager();
StringBuilder sb = new StringBuilder();
bool notFirst = false;
foreach (Site s in mgr.Sites) {
if (notFirst) {
sb.Append(',');
}
notFirst = true;
sb.Append(GetFromClauseForSite(s));
}
return sb.ToString();
}
return GetFromClauseForSite(site);
}
private ServerManager GetServerManager() {
return ManagementUnit.ReadOnlyServerManager;
}
private string GetFromClauseForSite(Site s) {
return "'" + Path.Combine(Environment.ExpandEnvironmentVariables(s.LogFile.Directory), "W3SVC" + s.Id.ToString()) + "\\*.log'";
}
private Site GetCurrentSite() {
if (ManagementUnit.ConfigurationPath.PathType == ConfigurationPathType.Site) {
ServerManager mgr = GetServerManager();
Site site = mgr.Sites[ManagementUnit.ConfigurationPath.SiteName];
return site;
}
return null;
}
}
モジュールの作成
IIS レポートを生成するには、モジュールが必要です。各モジュールには複数のレポート機能を含めることができ、各レポート機能には複数のレポートを含めることができます。また、各レポートには複数のレポート フィルターを含めることができます。説明を簡単にするために、レポート機能が 1 つであるモジュールを作成し、レポート機能にはレポートが 1 つだけ含まれるようにします。このレポートには、To Date と From Date の 2 つのフィルターがあり、指定した 2 つの日付の間のデータを選択できるようにします。
TestModule は IExtensibilityManager を取得し、TestReportingFeature を拡張機能マネージャーに登録します。IIS Reports モジュールは、実行時に IExtensibilityManager に拡張機能 ReportingFeature を照会し、レポートを表示します。
[プロジェクト] メニューの [参照の追加] をクリックし、[参照] タブで \Windows\system32\inetsrv ディレクトリを検索して、Microsoft.Web.Management.IisReports.Client.dll への参照を追加します。
internal class TestModule : Module {
private ReportingFeature testReportingFeature;
protected override void Initialize(IServiceProvider serviceProvider, Microsoft.Web.Management.Server.ModuleInfo moduleInfo) {
base.Initialize(serviceProvider, moduleInfo);
IExtensibilityManager extensibilityManager =
(IExtensibilityManager)serviceProvider.GetService(typeof(IExtensibilityManager));
Debug.Assert(extensibilityManager != null, "Extensibility Manager is null");
testReportingFeature = new TestReportingFeature(this);
if (extensibilityManager != null) {
extensibilityManager.RegisterExtension(typeof(ReportingFeature), testReportingFeature);
}
}
}
このデモンストレーション用に使用しているレポート定義は ChartReportDefinition です。IIS Reports では、3 種類のレポート定義を使用できます。最も高度なレポート定義である ChartReportDefinition では、データのグラフとテーブルが作成され、TableReportDefinition ではデータのテーブルのみが表示されます。TestReportDefinition は、日付に基づいてデータをフィルター処理する FromDate と ToDate という 2 つのフィルターを公開します。TestReportDefinition には、内部でサービス プロキシおよびモジュール サービスを呼び出してオブジェクト配列を取得する GetData メソッドがあります。次に、オブジェクト配列からデータテーブルを作成します。このデータテーブルは、グラフやテーブルを表示するために IIS Reports で使用されます。
internal class TestReportDefinition : ChartReportDefinition {
private ReportFilter[] _filters;
public TestReportDefinition(ReportingFeature feature)
: base(feature, "TestReportName", "Test Report Name", ReportCategory.WebServer) {
ReportFilter filter1 =
new ReportFilter("FromDate", "From Date", DataType.DateTime, DateTime.Now.Subtract(new TimeSpan(30, 0, 0, 0)), true);
ReportFilter filter2 =
new ReportFilter("ToDate", "To Date", DataType.DateTime, DateTime.Now, true);
_filters = new ReportFilter[] { filter1, filter2 };
}
public override string XValueColumn {
get {
return "Site";
}
}
public override IList<string> YValueColumns {
get {
return new string[] { "Hits" };
}
}
public override IList<string> Columns {
get {
return new string[] { "Site", "Hits" };
}
}
public override IEnumerable<ReportFilter> Filters {
get {
return _filters;
}
}
protected override DataTable GetData(IDictionary<string, object> arguments) {
Hashtable filters = new Hashtable();
foreach (KeyValuePair<string, object> filter in arguments) {
filters.Add(filter.Key, filter.Value);
}
object[] data = ((TestReportingFeature)Feature).ServiceProxy.GetReport(filters);
object[] row;
ArrayList rows = (ArrayList)data[1];
DataTable table = new DataTable();
table.Columns.Add("site", typeof(string));
table.Columns.Add("hits", typeof(int));
for (int i = 0; i < rows.Count; i++) {
DataRow tableRow = table.NewRow();
row = (object[])rows[i];
tableRow["site"] = (string)row[0];
tableRow["hits"] = (int)row[1];
table.Rows.Add(tableRow);
}
return table;
}
}
ServiceProxy の作成
internal class TestReportServiceProxy : ModuleServiceProxy {
public object[] GetReport(IDictionary arguments) {
return (object[])Invoke("GetReport", arguments);
}
}
その他
ClassesInterop.cs
Logparser は COM オブジェクトを返すので、interop.cs が必要です。このファイルは、Interop.cs からダウンロードできます。
AssemblyRef.cs
このクラスは、クライアント モジュールを読み込むためにモジュール プロバイダーによって使用されます。
internal static class AssemblyRef {
private static string testReportClient;
internal static string TestReportClient {
get {
if (testReportClient == null) {
AssemblyName assemblyName = typeof(AssemblyRef).Assembly.GetName();
string assemblyFullName = assemblyName.FullName;
testReportClient = assemblyFullName.Replace(assemblyName.Name, "TestIisReportsClient");
}
return testReportClient;
}
}
}