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」を追加しておきます。
サンプルプログラム
こちらのチュートリアル
同期 HTTP ハンドラーの作成
そして、こちらのサイトを参考にしました。
.NETでコントローラを作ってみる
アクセスすると「Hello World」と表示するハンドラーを作成してみます。
・Sample.cs
- using System.Web;
- namespace Sample {
- public class MyHandler : System.Web.IHttpHandler {
- public bool IsReusable {
- get { return false; }
- }
- public void ProcessRequest(HttpContext context) {
- context.Response.ContentType = "text/html";
- context.Response.Write("Hello World");
- }
- }
- }
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
- <configuration>
- <system.webServer>
- <handlers>
- <add verb="*" path="*.hello"
- name="hello_handler"
- type="Sample.MyHandler"/>
- </handlers>
- </system.webServer>
- </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
ここまで設定できたら、IISマネージャーを表示。
Default Web Siteの「ハンドラーマッピング」をダブルクリック。
「hello_handler」が認識されています。
ここで、「ページに関連する構成データが無効であるため、要求されたページにアクセスできません。」という
エラーが表示される場合は、ASP.NET 4.6がインストールされていない可能性が高いです。
ちゃんとASP.NET 4.6やISAPI拡張がインストールされているか確認します。
これでハンドラーの設定は完了です。
動作テスト
トップページを表示。
http://[server]/sample.testを表示すると404エラー。
ハンドラーに登録した拡張子http://[server]/sample.helloを表示すると
「Hello World」と表示されます。
リダイレクト
リダイレクトしたい場合はこんなプログラムになります。
- using System.Web;
- namespace Sample {
- public class MyHandler : System.Web.IHttpHandler {
- public bool IsReusable {
- get { return false; }
- }
- public void ProcessRequest(HttpContext context) {
- //context.Response.ContentType = "text/html";
- //context.Response.Write("Hello World");
- // リダイレクト
- HttpContext.Current.Response.Redirect("https://www.google.co.jp/");
- }
- }
- }
拡張子helloだとリダイレクト。
データベース接続
こちらでOracleに接続してみました。
C#からOracle 11g XEへODP.NETで接続
ハンドラー内でデータベースに接続するような処理も実行できるのか試してみます。
- using System.Web;
- using Oracle.ManagedDataAccess.Client;
- namespace Sample {
- public class MyHandler : System.Web.IHttpHandler {
- public bool IsReusable {
- get { return false; }
- }
- public void ProcessRequest(HttpContext context) {
- //context.Response.ContentType = "text/html";
- //context.Response.Write("Hello World");
- // リダイレクト
- //HttpContext.Current.Response.Redirect("https://www.google.co.jp/");
- // データベース接続
- context.Response.ContentType = "text/html";
- OracleConnection con = new OracleConnection();
- string dataSource = "(DESCRIPTION = (ADDRESS_LIST = (ADDRESS=(PROTOCOL = TCP)(HOST = 192.168.1.101)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = XE)))";
- con.ConnectionString = "User ID=orauser; Password=Passw0rd; Data Source=" + dataSource + ";";
- con.Open();
- string sql = "SELECT * FROM sample";
- OracleCommand cmd = new OracleCommand(sql, con);
- OracleDataReader reader = cmd.ExecuteReader();
- while ( reader.Read() ) {
- context.Response.Write(string.Format("{0}:{1}<br>", reader["id"], reader["val"]));
- }
- reader.Close();
- con.Close();
- }
- }
- }
C:\inetpub\wwwroot\\binに「Oracle.ManagedDataAccess.dll」をコピー。
うまく行きました。
Cookieの内容を読み取って、まだログインしていなかったらログイン画面へ。
Cookieに設定している内容でデータベースに問い合わせて、閲覧権限をチェック。
...といったこともハンドラーで実施できそうです。
【参考URL】
IIS + ASP.NET 本番サーバ移行のトラブル備忘録
このハンドラーに対して指定されたモジュールが、モジュールの一覧にありません。
IHttpModuleとIHttpHandle
.NETでコントローラを作ってみる
HTTP ハンドラと HTTP モジュールの概要
チュートリアル : 同期 HTTP ハンドラーの作成
- 関連記事
-
- Redmine 3.4.3をUbuntu Server 16.04へインストール(PostgreSQL, rbenv使用)
- Ubuntu 16.04にrbenvでRubyのバージョンを管理する
- IIS 10.0 + C#で自作したHTTPハンドラー(IHttpHandle)を動作させる
- Ubuntu Server 16.04に固定IPを設定
- Ubuntu + Android Studioで実機をUSBに接続してデバッグ
コメント