IIS 10.0 + C#で自作したHTTPハンドラー(IHttpHandle)を動作させる

IISで動くアプリケーションで、特定のURLの時に処理を実行したい。
(ログの出力や認証チェック等)

Java Servletだとフィルターで実装する処理でしょうか。


調べてみると、HttpModuleやHttpHandleをC#で作成すれば願いが叶いそうです。
今回は独自のHTTPハンドラーをC#で作成。
IISに設定してみます。



IIS 10.0のインストール



Windows Server 2016で試してみます。
IISのインストールは以前行っているのでこちらを参考にします。
Windows Server 2016 にIIS 10.0をインストールし、ASP.NETを有効化


インストール時のポイントですが、
「ASP.NET 4.6を必ず有効にすること」

ASP.NETやISAPI拡張がインストールされていないと、ハンドラーを設定した時、


このハンドラーに対して指定されたモジュールが、モジュールの一覧にありません。
スクリプト マップ ハンドラー マッピングを追加する場合は、
モジュール一覧にIsapiModule または CgiModule が存在している必要があります。




1. 500.19 エラー
HTTP エラー 500.19 - Internal Server Error
ページに関連する構成データが無効であるため、要求されたページにアクセスできません。
エラー コード 0x80070021
構成エラー この構成セクションをこのパスで使用できません。
この問題は、親レベルでセクションがロックされているときに発生します。
ロック状態は既定で設定されているか (overrideModeDefault="Deny")、または overrideMode="Deny"
もしくは従来の allowOverride="false" を含んだ場所タグによって明示的に設定されます。




こういったエラーが表示され動いてくれません。
ハマりました。


インストール時に忘れず「ASP.NET 4.6」を追加しておきます。

804_01.png





サンプルプログラム



こちらのチュートリアル
同期 HTTP ハンドラーの作成
そして、こちらのサイトを参考にしました。
.NETでコントローラを作ってみる


アクセスすると「Hello World」と表示するハンドラーを作成してみます。

・Sample.cs


  1. using System.Web;
  2. namespace Sample {
  3.     
  4.     public class MyHandler : System.Web.IHttpHandler {
  5.         
  6.         public bool IsReusable {
  7.             get { return false; }
  8.         }
  9.         
  10.         public void ProcessRequest(HttpContext context) {
  11.             context.Response.ContentType = "text/html";
  12.             context.Response.Write("Hello World");
  13.         }
  14.     }
  15. }




IsReusableが、インスタンスを使いまわしてよいか(だと思う)
スレッドセーフな処理ならtrueを返して問題ないと思いますが、今回は先人に習いfalseにしておきました。

ProcessRequestが処理の実体です。
レスポンスに「Hello World」と書き込んでやります。


コンパイルはこんなバッチを作成して行いました。

・build.bat


@echo off
set csc="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
set opt=/nologo /t:library

%csc% %opt% Sample.cs




バッチを実行するとSample.dllが生成されます。




ハンドラーの設定



作成したハンドラーをIIS設定してみます。

ハンドラーを有効化するWeb.configを作成。
C:\inetpub\wwwrootに配置します。

・Web.config


  1. <configuration>
  2. <system.webServer>
  3.     <handlers>
  4.      <add verb="*" path="*.hello"
  5.         name="hello_handler"
  6.         type="Sample.MyHandler"/>
  7.     </handlers>
  8. </system.webServer>
  9. </configuration>




verb:このハンドラーを有効にするmethod。
GETやPOSTのみに反応させる場合は指定しますが、今回はすべて(*)を指定しています。

path:このハンドラーを反応させる要求パス。
「*.hello」としているので、拡張子がhelloのURLの場合に反応します。
「target/*.hello」のようにURLを含めた指定も可能です。

name:このハンドラーを識別するための名前。
他のハンドラーと重複しない任意の名称を設定します。

type:ハンドラークラス
今回作成したハンドラーは「Sample」名前空間の「MyHandler」クラスなので「Sample.MyHandler」と指定します。
名前空間がない場合は単に「MyHandler」のように指定すればOKです。


続いて、「C:\inetpub\wwwroot\bin」フォルダを作成。
ビルドした「Sample.dll」を配置します。

最終的にC:\inetpub\wwwrootはこのようになります。
※仮想ディレクトリにハンドラーを設定たい場合は、該当仮想ディレクトリに同じ構成で配置します。


C:\inetpub\wwwroot\
Web.config
\bin\Sample.dll



804_02.png

804_03.png


ここまで設定できたら、IISマネージャーを表示。
Default Web Siteの「ハンドラーマッピング」をダブルクリック。

804_04.png


「hello_handler」が認識されています。

804_05.png


ここで、「ページに関連する構成データが無効であるため、要求されたページにアクセスできません。」という
エラーが表示される場合は、ASP.NET 4.6がインストールされていない可能性が高いです。
ちゃんとASP.NET 4.6やISAPI拡張がインストールされているか確認します。


これでハンドラーの設定は完了です。





動作テスト



トップページを表示。

804_06.png


http://[server]/sample.testを表示すると404エラー。

804_07.png


ハンドラーに登録した拡張子http://[server]/sample.helloを表示すると
「Hello World」と表示されます。

804_08.png




リダイレクト



リダイレクトしたい場合はこんなプログラムになります。


  1. using System.Web;
  2. namespace Sample {
  3.     
  4.     public class MyHandler : System.Web.IHttpHandler {
  5.         
  6.         public bool IsReusable {
  7.             get { return false; }
  8.         }
  9.         
  10.         public void ProcessRequest(HttpContext context) {
  11.             //context.Response.ContentType = "text/html";
  12.             //context.Response.Write("Hello World");
  13.             
  14.             // リダイレクト
  15.             HttpContext.Current.Response.Redirect("https://www.google.co.jp/");
  16.         }
  17.     }
  18. }




拡張子helloだとリダイレクト。

804_09.png

804_10.png





データベース接続



こちらでOracleに接続してみました。
C#からOracle 11g XEへODP.NETで接続

ハンドラー内でデータベースに接続するような処理も実行できるのか試してみます。


  1. using System.Web;
  2. using Oracle.ManagedDataAccess.Client;
  3. namespace Sample {
  4.     
  5.     public class MyHandler : System.Web.IHttpHandler {
  6.         
  7.         public bool IsReusable {
  8.             get { return false; }
  9.         }
  10.         
  11.         public void ProcessRequest(HttpContext context) {
  12.             //context.Response.ContentType = "text/html";
  13.             //context.Response.Write("Hello World");
  14.             
  15.             // リダイレクト
  16.             //HttpContext.Current.Response.Redirect("https://www.google.co.jp/");
  17.             
  18.             // データベース接続
  19.             context.Response.ContentType = "text/html";
  20.             
  21.             OracleConnection con = new OracleConnection();
  22.             string dataSource = "(DESCRIPTION = (ADDRESS_LIST = (ADDRESS=(PROTOCOL = TCP)(HOST = 192.168.1.101)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = XE)))";
  23.             
  24.             con.ConnectionString = "User ID=orauser; Password=Passw0rd; Data Source=" + dataSource + ";";
  25.             con.Open();
  26.             
  27.             string sql = "SELECT * FROM sample";
  28.             OracleCommand cmd = new OracleCommand(sql, con);
  29.             
  30.             OracleDataReader reader = cmd.ExecuteReader();
  31.             while ( reader.Read() ) {
  32.                 context.Response.Write(string.Format("{0}:{1}<br>", reader["id"], reader["val"]));
  33.             }
  34.             
  35.             reader.Close();
  36.             con.Close();
  37.         }
  38.     }
  39. }




C:\inetpub\wwwroot\\binに「Oracle.ManagedDataAccess.dll」をコピー。

804_11.png


うまく行きました。

804_12.png


Cookieの内容を読み取って、まだログインしていなかったらログイン画面へ。
Cookieに設定している内容でデータベースに問い合わせて、閲覧権限をチェック。
...といったこともハンドラーで実施できそうです。



【参考URL】

IIS + ASP.NET 本番サーバ移行のトラブル備忘録
このハンドラーに対して指定されたモジュールが、モジュールの一覧にありません。
IHttpModuleとIHttpHandle
.NETでコントローラを作ってみる
HTTP ハンドラと HTTP モジュールの概要
チュートリアル : 同期 HTTP ハンドラーの作成
関連記事

コメント

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
https://symfo.web.fc2.com/

PR

検索フォーム

月別アーカイブ