.NET TIPS

[ASP.NET]アプリケーション共通のロギングを行うには?(HTTPモジュール編)

山田 祥寛
2004/03/05

 別稿「TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)」では、アプリケーション共通のロギング機能をGlobal.asaxで実装する方法について紹介した。これとほとんど同様の動作を「HTTPモジュール」という機能を用いることでも実現できる。

 よく似た概念として「HTTPハンドラ」という概念があるが(別稿「TIPS:[ASP.NET]特定の拡張子に対するアクセスを制限するには?」や「TIPS:[ASP.NET]ASP.NETアプリケーションに独自の拡張子を追加するには?」を参照)、HTTPハンドラが「リクエストを直接に処理する」ためのものであったのに対し、HTTPモジュールは「リクエスト処理に特定の機能を付加する」ための役割を提供する。例えば、ASP.NETの認証、セッション、キャッシング、エラー・ハンドルなどは、内部的にはすべてHTTPモジュールによって提供されている機能である。

 まずは、HTTPモジュールが動作するまでの一連の手順を概観してみることにしよう。

1. HTTPモジュール・クラスを記述する

 HTTPモジュール・クラスのコードは以下のとおり。ロギング(ログ収集)のロジックそのものは、別稿「TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)」で紹介したものそのままなので、詳細はそちらを参照してほしい。

using System;
using System.Web;

using System.Data;
using System.Data.SqlClient;

namespace Com.Msn.Wings {
  public class CustomLogModule : IHttpModule {
    public void Init(HttpApplication application) {
      application.BeginRequest += (new EventHandler(this.Application_OnBeginRequest));
    }
    public void Dispose() {
      // リソースの解放処理などを記述
    }
    void Application_OnBeginRequest(Object sender , EventArgs e) {
      HttpContext context = ((HttpApplication)sender).Context;
      SqlConnection objDb = new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=nettips");
      SqlCommand objCom = new SqlCommand("SELECT * FROM accessLog WHERE url=@url AND accessDate=@accessDate",objDb);
      objCom.Parameters.Add("@url",context.Request.Url.ToString());
      objCom.Parameters.Add("@accessDate",DateTime.Now.ToString("yyyy/MM"));
      objDb.Open();
      SqlCommand objCom2;
      SqlDataReader objDr = objCom.ExecuteReader();
      if(objDr.HasRows){
        objDr.Close();
        objCom2 = new SqlCommand("UPDATE accessLog SET cnt=cnt+1 WHERE url=@url AND accessDate=@accessDate",objDb);
      }else{
        objDr.Close();
        objCom2 = new SqlCommand("INSERT INTO accessLog(url,accessDate,cnt) VALUES(@url,@accessDate,1)",objDb);
      }
      objCom2.Parameters.Add("@url",context.Request.Url.ToString());
      objCom2.Parameters.Add("@accessDate",DateTime.Now.ToString("yyyy/MM"));
      objCom2.ExecuteNonQuery();
      objDb.Close();
    }
  }
}
ロギングを行うHTTPモジュール・クラス(C#:CustomLogModule.cs)
 
Imports System
Imports System.Web

Imports System.Data
Imports System.Data.SqlClient

Namespace Com.Msn.Wings
  Public Class CustomLogModule : Implements IHttpModule
    Public Sub Init(application As HttpApplication) Implements IHttpModule.Init
      AddHandler application.BeginRequest, AddressOf Me.Application_OnBeginRequest
    End Sub
    ' BeginRequestイベントに、Application_OnBeginRequestプロシージャを関連付け
    Public Sub Dispose() Implements IHttpModule.Dispose
      ' リソースの解放処理などを記述
    End Sub
    Sub Application_OnBeginRequest(sender As Object, e As EventArgs)
      Dim application As HttpApplication = CType(sender, HttpApplication)
      Dim context As HttpContext = CType(sender, HttpApplication).Context
      Dim objDb As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=nettips")
      Dim objCom As New SqlCommand("SELECT * FROM accessLog WHERE url=@url AND accessDate=@accessDate",objDb)
      objCom.Parameters.Add("@url",context.Request.Url.ToString())
      objCom.Parameters.Add("@accessDate",DateTime.Now.ToString("yyyy/MM"))
      objDb.Open()
      Dim objCom2 As SqlCommand
      Dim objDr As SqlDataReader = objCom.ExecuteReader()
      If objDr.HasRows Then
        objDr.Close()
        objCom2 = New SqlCommand("UPDATE accessLog SET cnt=cnt+1 WHERE url=@url AND accessDate=@accessDate",objDb)
      Else
        objDr.Close()
        objCom2 = New SqlCommand("INSERT INTO accessLog(url,accessDate,cnt) VALUES(@url,@accessDate,1)",objDb)
      End If
      objCom2.Parameters.Add("@url",context.Request.Url.ToString())
      objCom2.Parameters.Add("@accessDate",DateTime.Now.ToString("yyyy/MM"))
      objCom2.ExecuteNonQuery()
      objDb.Close()
    End Sub
  End Class
End Namespace
ロギングを行うHTTPモジュール・クラス(VB.NET:CustomLogModule.vb)

 HTTPモジュール・クラスを定義するために必要な条件は、以下の3点だ。

(1)System名前空間、System.Web名前空間をインポートする

 HTTPモジュール・クラスを定義するには、最低限、System名前空間、System.Web名前空間を必要とする。もちろん、クラス内で必要なそのほかの名前空間も適宜、Imports(Using)ステートメントで追加すればよい。

(2)IHttpModuleインターフェイスを実装する

 ASP.NETはIHttpModuleインターフェイスを介してHTTPモジュールを呼び出すため、すべてのHTTPモジュール・クラスは必ずIHttpModuleインターフェイスを実装しなければならない。

(3)Initメソッド、Disposeメソッドを記述する

 IHttpModuleインターフェイスは、アプリケーションの起動時に呼び出されるInitメソッドと、終了時に呼び出されるDisposeメソッドを定義している。一般的には、Initメソッドで必要なリソースの確保やアプリケーション・イベントへのプロシージャの関連付けを行い、Disposeメソッドではリソースの解放処理を行う。

 上記サンプルでも、Initメソッド内部で、Application.BeginRequestイベントに対して、Application_OnBeginRequestプロシージャ(ロギング機能)の関連付けを行っている。一般的にイベントとプロシージャの関連付けは、以下の構文で行うことができる。

イベント名 += (new EventHandler(this.メソッド名));
C#の場合のイベントとメソッドの関連付け
 
AddHandler イベント名, AddressOf Me.プロシージャ名
VB.NETの場合のイベントとプロシージャの関連付け

 なお、ここではリソースの解放は必要ないので、Disposeメソッドは空の内容を定義しているのみである。インターフェイスを実装する場合には、メソッドでの処理がまったくなくても空のメソッドを記述する必要があるので注意すること。

2. HTTPモジュール・クラスを配置する

 HTTPモジュール・クラスは、使用に先立ってコマンドラインからコンパイルを行う必要がある。コンパイルの構文は以下のとおり。

>csc /t:library /r:System.dll /r:System.Web.dll /r:System.Data.dll CustomLogModule.cs
C#の場合のコンパイル方法
 
>vbc /t:library /r:System.dll /r:System.Web.dll /r:System.Data.dll CustomLogModule.vb
VB.NETの場合のコンパイル方法

 コンパイルに成功した場合C#、VB.NETいずれにおいても、CodeOutputHandler.dllが生成されるはずなので、これをアプリケーション・ルート配下の「\bin」フォルダにコピーすればよい。

3. web.configの設定を行う

 HTTPモジュールを有効化するには、アプリケーション・ルート配下の構成ファイル(web.config)に以下のような記述をする必要がある。これによって、CustomLogModuleアセンブリ内のCom.Msn.Wings.CustomLogModuleクラスがHTTPモジュール・クラスとして追加される。

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <system.web>
    <httpModules>
      <add name="CustomLogModule" type="Com.Msn.Wings.CustomLogModule, CustomLogModule" />
    </httpModules>
  </system.web>
</configuration>
HTTPモジュール・クラスを追加したweb.config

 以上で、カスタムのHTTPモジュール・クラスの用意は完了だ。別稿「TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)」で見たように、アプリケーション配下の任意のURLにアクセスすることで、自動的にアクセス情報がデータベースに記録されていくことを確認してほしい(ただし、Global.asaxのときにそうであったように、ASP.NETが処理の対象として認識するファイルに限定される。「.html」や「.txt」のようなファイルを含めてロギングを行う方法については、別稿「TIPS:[ASP.NET].htmlや.pdfファイルをフォーム認証やロギングの対象にするには?」を参照)。

 なお、本稿と別稿「TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)」の両方を参照して、Global.asaxとHTTPモジュール、いずれを用いればよいのか迷われた方もいるかもしれない。しかし、両者には一点決定的な違いがある。Global.asaxはアプリケーション単位にしか配置することができないが、HTTPモジュールはマシン(サーバ)単位に配置できるという点である。HTTPモジュールをサーバ単位に配置することで、サーバ共通のロギングが可能となる。マシン単位の配置を行う方法については、後日あらためて詳述することにしたい。End of Article

カテゴリ:Webフォーム 処理対象:ログ
使用ライブラリ:HorizontalAlignment列挙体(System.Windows.Forms名前空間)
関連TIPS:[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)
関連TIPS:[ASP.NET]特定の拡張子に対するアクセスを制限するには?
関連TIPS:[ASP.NET]ASP.NETアプリケーションに独自の拡張子を追加するには?
関連TIPS:[ASP.NET].htmlや.pdfファイルをフォーム認証やロギングの対象にするには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]アプリケーション共通のロギングを行うには?(Global.asax編)
[ASP.NET]アプリケーションにログ参照のユーティリティを追加するには?
[ASP.NET]ASP.NETアプリケーションに独自の拡張子を追加するには?
[ASP.NET]特定の拡張子に対するアクセスを制限するには?
[ASP.NET].htmlや.pdfファイルをフォーム認証やロギングの対象にするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」

@IT Special

- PR -

TechTargetジャパン

Insider.NET フォーラム 新着記事
  • Visual Studio 2017が目指す世界とは? (2017/3/24)
     Visual Studio 2017はもはやWindowsアプリ開発者のためだけのものではない。どんなアプリを開発できるのかを見てみよう
  • foreachループで現在の繰り返し回数を使うには? (2017/3/23)
     LINQのSelect拡張メソッドを使用して、foreachループの中で現在が何回目の繰り返しなのか、そのインデックスを得る方法を紹介する(C# 7/VB 15対応)
  • Listの要素を並べ替えるには? (2017/3/22)
     LINQのOrderBy/ThenByなどの拡張メソッドとListクラスのSortメソッドを利用して、Listの要素を並べ替える方法を解説する
  • .NET Portability Analyzer (2017/3/21)
     .NET Portability Analyzerは、さまざまなプラットフォームをまたいだ.NETプログラムの移植性をチェックするためのツール
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

イベントカレンダー

PickUpイベント

- PR -

アクセスランキング

もっと見る

ホワイトペーパーTechTargetジャパン

注目のテーマ

Insider.NET 記事ランキング

本日 月間
ソリューションFLASH