.NET TIPS

[ASP.NET]ASP.NETアプリケーションに独自の拡張子を追加するには?

山田 祥寛
2004/02/20

 別稿「TIPS:[ASP.NET]特定の拡張子に対するアクセスを制限するには?」「TIPS:[ASP.NET]特定のサービスを無効にするには?」では、ASP.NETにあらかじめ用意されたHTTPハンドラ・クラスの設定を変更することで、ある特定の拡張子の挙動を無効にしたり、アクセスを禁止したりする方法を紹介した。それらですでに何度か述べているように、HTTPハンドラ・クラスは初歩的なアプリケーション構築に際してはほとんど意識する必要がないが、サイト(アプリケーション)管理者の視点から見たときにはなかなかに有用な代物である。HTTPハンドラ・クラスを利用することで、サイト/アプリケーション単位の処理を一元的に規定することができるからだ。本稿では、既存のHTTPハンドラ・クラスを利用するのではなく、新しいHTTPハンドラ・クラスを自作して、ASP.NETに独自の機能を追加する方法を紹介する。

 今回作成する機能の概要は、以下のとおりである。

 アプリケーション配下のソース・コードをブラウザ上から閲覧できるようにする。

 例えば、

http://localhost/netIns/md5_sha1_vb.aspx

でアクセス可能なWebフォーム・ページのソース・コードを参照したいと思ったら、

http://localhost/netIns/md5_sha1_vb.aspx.code

のように、末尾に拡張子「.code」を付加してWebページにアクセスする。これによって、sample.aspxのソース・コードがブラウザ上に出力されるという機能である。もちろん、拡張子「.code」を持ったファイルが、サーバ上に実在する必要はない。

拡張子「.code」のソース・コード出力機能
対応するファイルのソース・コードを行番号付きで出力する。独自のHTTPハンドラ・クラスを自作することにより、この機能が実現できる。

 それではさっそく、カスタム(独自)のHTTPハンドラ・クラスを動作させるための一連の手順を見ていくことにしよう。

1. カスタムのHTTPハンドラ・クラスを記述する

 C#とVB.NETを例に、独自のHTTPハンドラ・クラスを記述してみることにしよう。

using System;
using System.IO;
using System.Web;
using System.Text;

namespace Com.Msn.Wings {
  public class CodeOutputHandler : IHttpHandler {
    public bool IsReusable {
      get {
        return true;
      }
    }
    public void ProcessRequest(HttpContext context) {
      String strTmp = context.Request.PhysicalPath;
      // リクエストURLの物理パスから「.code」を取り除いた絶対パスを取得
      String strPth = Path.Combine(Path.GetDirectoryName(strTmp), Path.GetFileNameWithoutExtension(strTmp));
      StreamReader objSrd = new StreamReader(strPth, Encoding.GetEncoding("Shift_JIS"));
      HttpResponse res = context.Response;
      res.Write("<html>");
      res.Write("<head><title>" + Path.GetFileNameWithoutExtension(strTmp) + "</title></head>");
      res.Write("<body>");
      res.Write("<h1>" + Path.GetFileNameWithoutExtension(strTmp) + "</h1>");
      res.Write("<table border='1'>");
      String color;
      int cnt=0;
      while (objSrd.Peek()>-1) {
        // 奇数行・偶数行で背景色を交互に切り替え
        if (cnt % 2 == 0) {
          color = "LightGoldenrodYellow";
        } else {
          color = "PaleGoldenrod";
        }
        cnt++;
        res.Write("<tr bgcolor='" + color + "'>");
        res.Write("<th align='right'>" + cnt + "</th>");
        // 対象のファイルをテキストファイルとして読み込み、行番号付きで出力
        res.Write("<td>" + context.Server.HtmlEncode(objSrd.ReadLine()).Replace("\t", "&nbsp;&nbsp;") + "</td></tr>");
      }
      res.Write("</body>");
      res.Write("</html>");
      objSrd.Close();
    }
  }
}
カスタムのHTTPハンドラ・クラス(C#:CodeOutputHandler.cs)
 
Imports System
Imports System.IO
Imports System.Web
Imports System.Text
Imports Microsoft.VisualBasic

Namespace Com.Msn.Wings
  Public Class CodeOutputHandler : Implements IHttpHandler
    Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable
      Get
        Return True
      End Get
    End Property
    Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
      Dim strTmp As String=context.Request.PhysicalPath
      ' リクエストURLの物理パスから「.code」を取り除いた絶対パスを取得
      Dim strPth As String=Path.Combine(Path.GetDirectoryName(strTmp), Path.GetFileNameWithoutExtension(strTmp))
      Dim objSrd As New StreamReader(strPth,Encoding.GetEncoding("Shift_JIS"))
      With context.Response
        .Write("<html>")
        .Write("<head><title>" & Path.GetFileNameWithoutExtension(strTmp) & "</title></head>")
        .Write("<body>")
        .Write("<h1>" & Path.GetFileNameWithoutExtension(strTmp) & "</h1>")
        .Write("<table border='1'>")
        Dim color As String
        Dim cnt As Integer=0
        Do While objSrd.Peek()>-1
          ' 奇数行・偶数行で背景色を交互に切り替え
          If cnt Mod 2=0 Then
            color="LightGoldenrodYellow"
          Else
            color="PaleGoldenrod"
          End If
          cnt=cnt+1
          .Write("<tr bgcolor='" & color & "'>")
          .Write("<th align='right'>" & cnt & "</th>")
          ' 対象のファイルをテキストファイルとして読み込み、行番号付きで出力
          .Write("<td>" & context.Server.HtmlEncode(objSrd.ReadLine()).Replace(Chr(9), "&nbsp;&nbsp;") & "</td></tr>")
        Loop
        .Write("</body>")
        .Write("</html>")
      End With
      objSrd.Close()
    End Sub
  End Class
End Namespace
カスタムのHTTPハンドラ・クラス(VB.NET:CodeOutputHandler.vb)

 HTTPハンドラ・クラスを定義する場合のポイントは、以下の4点だ。

(1)System名前空間、System.Web名前空間は必須

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

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

 すべてのHTTPハンドラ・クラスは必ずIHttpHandlerインターフェイス(System.Web名前空間)を実装しなければならない。ASP.NETは、このインターフェイスにより実装されるIsReusableプロパティやProcessRequestメソッドを呼び出す。

(3)IsReusableプロパティを記述する

 IsReusableプロパティは、HTTPハンドラ・クラスのインスタンスをほかの要求で再利用できるかどうかを示す値を返す。インスタンスが再利用可能であるかどうかに応じて、true/falseのいずれかを「固定値」として返すようにするのが一般的だ。

(4)実処理はProcessRequestメソッドを記述する

 HTTPハンドラ・クラスの実処理を記述するのがProcessRequestメソッドの役割だ。ProcessRequestメソッドに渡されるHttpContextオブジェクトを介することで、Application、Cache、Request、Response、Server、Session、Trace、Userなど主要な「組み込みオブジェクト」にアクセスすることができる。

 本サンプルでは、ProcessRequestメソッド内で、リクエストURLから拡張子「.code」を取り除いたファイル名を抽出し、StreamReaderクラス(System.IO名前空間)でコードを読み込み、Responseオブジェクトに対して出力を行っている。

2. HTTPハンドラ・クラスを配置する

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

C#の場合のコンパイル方法:
> csc /t:library /r:System.dll /r:System.Web.dll CodeOutputHandler.cs

VB.NETの場合のコンパイル方法:
> vbc /t:library /r:System.dll /r:System.Web.dll CodeOutputHandler.vb

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

3. web.configの設定を行う

 次に、アプリケーション・ルート配下のweb.configに以下の設定を追加する。別稿「TIPS:[ASP.NET]特定の拡張子に対するアクセスを制限するには?」でも紹介したように、これによって、いま作成したCodeOutputHandler.dllアセンブリ内のCom.Msn.Wings.CodeOutputHandlerクラスが拡張子「.code」処理用のHTTPハンドラ・クラスとして追加される。

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <system.web>
    <httpHandlers>
      <add verb="GET,HEAD" path="*.code"
        type="Com.Msn.Wings.CodeOutputHandler,CodeOutputHandler" />
    </httpHandlers>
  </system.web>
</configuration>
拡張子「.code」の設定を追加したweb.config

4. IISに拡張子のマッピングを行う

 ただし、web.configの設定だけでは、カスタムの拡張子は正常には処理されない。なぜならHTTPハンドラ・クラスへの振り分けはASP.NETエンジン(aspnet_isapi.dll)が行うからだ。「.code」はIISのデフォルト設定では認識されない拡張子であるから、当然、「.code」へのリクエストがあってもaspnet_isapi.dllは起動しない。

 そこで、拡張子「.code」がHTTPハンドラ・クラスで処理されるようにするためには、IIS上で「.code」とASP.NETエンジン(aspnet_isapi.dll)との関連付けを行う必要がある。この方法については、別稿「TIPS:[ASP.NET].htmlや.pdfファイルをフォーム認証やロギングの対象にするには?」で紹介しているので、そちらを参照してほしい。

 以上で、カスタムのHTTPハンドラ・クラスの用意は完了だ。設定したアプリケーション・ルート配下またはそれよりも下位階層にある任意のURLに「.code」を付加することで、本稿冒頭のようなソース・リストが表示されれば成功である。End of Article

カテゴリ:Webフォーム 処理対象:構成ファイル
使用キーワード:<httpHandlers>要素
使用ライブラリ:IHttpHandlerインターフェイス(System.Web名前空間)
使用ライブラリ:StreamReaderクラス(System.IO名前空間)
関連TIPS:[ASP.NET]特定の拡張子に対するアクセスを制限するには?
関連TIPS:[ASP.NET]特定のサービスを無効にするには?
関連TIPS:[ASP.NET].htmlや.pdfファイルをフォーム認証やロギングの対象にするには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]特定の拡張子に対するアクセスを制限するには?
[ASP.NET]アプリケーションにログ参照のユーティリティを追加するには?
[ASP.NET]動的にJPEG画像を作成するには?
[ASP.NET]ユーザーから入力されたデータを任意のあて先にメールするには?
[ASP.NET]特定のサービスを無効にするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間