はじめに
.NET Frameworkには画像を生成するためのクラスが含まれています。このクラスを使えばASP.NETの中で画像を自動生成させることが簡単に実現できます。また、アクセスカウンタの実行例では、画像の生成とダウンロードにashxファイルを利用しています。ashxファイルの利用はドキュメントに説明されていませんが、画像のようなデータを直接ブラウザにダウンロードする場合に適した方法です。
ここではアクセスカウンタの実装を例に、画像を自動生成する方法、およびashxファイルの利用方法について説明します。
対象読者
.NET Frameworkを用いてWebアプリケーションを開発している方。
必要な環境
SQL ServerとASP.NETが実行できるWindows XP、またはWindows 2003 Server。
サンプルの実行環境の構築
サンプルではカウンタのデータの保持にSQL Serverを利用しています。データベース側の準備として、まずテーブルの生成と初期データ(カウンタID:1、初期値:0)の追加を行うために以下のSQL文をクエリアナライザなどから実行してください。
CREATE TABLE [dbo].[counterTable] ( [counterID] [int] NOT NULL , [number] [int] NOT NULL ) ON [PRIMARY] GO INSERT INTO counterTable(counterID, number) VALUES(1, 0) GO
複数のカウンタを利用したい場合には、カウンタIDが1以外のデータを必要なだけ追加してください。
次にストアドプロシージャを登録します。以下のSQL文を同じくクエリアナライザなどから実行してください。
CREATE PROCEDURE GETCOUNT @param1 int AS UPDATE COUNTERTABLE SET NUMBER = NUMBER + 1 WHERE COUNTERID = @param1 SELECT NUMBER FROM COUNTERTABLE WHERE COUNTERID = @param1 GO
このストアドプロシージャは呼び出すときに引数としてカウンタIDを必要とします。処理としては、渡されたカウンタIDのデータを1つ繰り上げてその数字を返します。ここまででデータベース側の準備は終了です。
自分でデータベースを含めてサーバを管理している場合は、ASP.NETの実行ユーザにデータベースのアクセス権を付与する必要があります。このようなASP.NETからデータベースを利用する方法については書籍『ASP.NETでいってみよう』で学習することをおすすめします。
次にサンプルソースに含まれる「counter.ashx」、「countertest.html」の2つのファイルをサーバ上の同じフォルダに配置します。このとき「counter.ashx」の中に記述されているデータベースへの接続文字列を、利用しているサーバに合わせて修正する必要があります。この時点で「countertest.html」にアクセスし、カウンタが正常に表示されればOKです。
なお、各種設定の変更については、プログラム中のコメントと「ReadMe.txt」を参照してください。ここで「countertest.html」ファイルでカウンタを表示するために記述しているタグは以下のようになっています。
<img src="counter.ashx?ID=1">
これは普通のimg
タグですので、「countertest.html」のようにhtmlファイルからでも利用可能です。カウンタを複数設置する場合は、img
タグ内でID
に渡す数字をデータベースに作成した別のカウンタIDに合わせてください。
ashxファイルの概要
ashxファイルはIHttpHandlerインタフェースを実装したクラスを、動的にコンパイルして実行してくれるファイルです。
IHttpHandler
インタフェースはASP.NETの処理の中核といえるインタフェースであり、Page
クラスもIHttpHandler
インタフェースを継承しています。Page
クラスのようにユーザインタフェースを提供するためのさまざまな機能は持っていませんが、それだけにサンプルのような画像などのデータを直接ダウンロードする場合にはashxファイルの利用が適しています。
ashxファイルは以下のような構造をとります。
<%@ WebHandler language="C#" class="MyImage" %> public class MyImage:IHttpHandler { public bool IsReusable { get { return(true); } } public void ProcessRequest(HttpContext context) { ・・・ } }
1行目はWebHandler
ディレクティブです。ここでは使用する言語と作成するクラス名を属性として記述します。作成するクラスはIHttpHandler
インタフェースを継承するのでIsReusable
メソッドとProcessRequest
メソッドを実装しなければなりません。
IsReusable
メソッドはこのクラスが再利用できるかどうかをASP.NETが判定するためのメソッドです。通常true
を返すように実装しておけば問題ないでしょう。
ProcessRequest
メソッドの実装がプログラミング作業の中心になります。このメソッドに渡されるHttpContext
オブジェクトを通してブラウザからのリクエストを取り出し、ブラウザに渡すレスポンスを作成していくことになります。サンプルでは説明がしやすいようにいくつかの内部メソッドを呼び出す形でここの処理を行っています。順を追って説明していきます。
ブラウザから渡されるデータの取り出し
最初にブラウザから渡されるカウンタIDの値を取り出しています。
private string getCounterID(HttpContext context) { return context.Request.QueryString["ID"]; }
ブラウザからはクエリ文字列によってカウンタIDの値が渡されてきます。この場合、HttpContext
オブジェクトが持つRequest
オブジェクトを通してその値を取り出します。
再読み込み時にカウントアップしないための工夫
再読み込みによりカウンタの数字が増えてしまうのを防ぐため、サンプルではCookieを利用しています。
private string checkCookie(HttpContext context) { // 同じブラウザから同じセッション内で接続された際は // Cookieに保存してある数字を使う if(context.Request.Cookies["counter"]!=null) return context.Request.Cookies["counter"].Value; else return ""; }
Request
オブジェクトを通してCookieの存在をチェックし、その値を取り出しています。Cookieにはカウンタに表示された数字を保存していますので、再読み込み時にはその数字を利用し、データベースへの接続を行いません。
ストアドプロシージャを利用したデータの取り出し
Cookieが存在していない場合、つまりブラウザからの最初の接続のときはデータベースからカウンタに表示する数字を取り出します。
private string getCount(string id) { string countString; if(id==null) countString = errString; else { SqlConnection cn = new SqlConnection(connectionString); // コマンドをストアドプロシージャを利用するように設定 SqlCommand cmd = new SqlCommand(spName, cn); cmd.CommandType = CommandType.StoredProcedure; // パラメータの設定 SqlParameter p1 = cmd.Parameters.Add("@param1", SqlDbType.Int); p1.Value = int.Parse(id); try { cn.Open(); // データベースから数字を取り出し // 指定された桁数まで0で埋める countString = cmd.ExecuteScalar().ToString() .PadLeft(countLength, '0'); } catch { countString = errString; } finally { cn.Close(); } } return countString; }
ストアドプロシージャを利用する場合はSqlCommand
オブジェクトのCommndType
プロパティにCommandType.StoredProcedure
を設定します。また、ここで利用するストアドプロシージャは単一の値を返しますので、ExecuteScalar
メソッドを利用してその値を取り出しています。
カウンタ画像の生成
カウンタ画像の生成は多少複雑な処理になっています。
private Bitmap getBmp(string cnt) { // StringFormatの設定 StringFormat strfmt = new StringFormat(); CharacterRange[] characterRanges = {new CharacterRange(0, cnt.Length)}; strfmt.SetMeasurableCharacterRanges(characterRanges); strfmt.LineAlignment = StringAlignment.Center; // ベースになる画像の作成 Bitmap bmp = new Bitmap(baseWidth, baseHeight); Graphics g = Graphics.FromImage(bmp); g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; g.FillRectangle(new SolidBrush(Color.FromName(bgColor)), 0, 0, baseWidth, baseHeight); // 数字の描き込み Font f = new Font(fontName, fontSize); g.DrawString(cnt, f, new SolidBrush(Color.FromName(fontColor)), new RectangleF(0, 0, baseWidth, baseHeight), strfmt) // 数字を書いた部分の大きさの計測 Region[] rg = g.MeasureCharacterRanges( cnt, f , new RectangleF(0, 0, baseWidth, baseHeight), strfmt); RectangleF rfbase = rg[0].GetBounds(g); int iEmHeight = f.FontFamily.GetEmHeight(f.Style); int iCellAscent = f.FontFamily.GetLineSpacing(f.Style) - f.FontFamily.GetCellDescent(f.Style); RectangleF rf = new RectangleF(rfbase.Left-1, rfbase.Top, rfbase.Width+2, rfbase.Height / iEmHeight * iCellAscent); // 数字部分の切り出しと枠線の描き込み Bitmap cb = bmp.Clone(rf, bmp.PixelFormat); Graphics cg = Graphics.FromImage(cb); cg.DrawRectangle(new Pen(Color.FromName(borderColor)), 0, 0, rf.Width-1, rf.Height-1); return cb; }
カウンタに表示する数字のフォント、桁数を設定で変更できるようにしています。このフォントや桁数に合わせてカウンタ画像の大きさを変更するため、一度文字を書き込んでその文字の大きさを計測し、必要な部分だけを切り出してダウンロード用の画像とする、という処理を記述しています。
画像のダウンロード
画像のダウンロード時には、ダウンロードするデータのMIME Typeを指定する必要があります。
// 画像の形式を指定してメモリ上に保存 MemoryStream mem = new MemoryStream(); counterBmp.Save(mem, ImageFormat.Png); // 画像のダウンロード context.Response.ContentType = "image/png"; context.Response.BinaryWrite(mem.ToArray());
サンプルでは生成したカウンタ画像をPNG形式に保存し、ContrentType
にPNGのMIME Typeを指定した上で、BinaryWrite
メソッドを利用して画像をダウンロードしています。
まとめ
ASP.NETは柔軟性が非常に高く、さまざまな処理を独自の実装に置き換えることが可能です。ashxファイルはaspxファイルを置き換えることができるものであり、そういったASP.NETの柔軟性を学ぶ最初の手がかりとして手軽に取り組むことができる便利なファイルです。
残念ながらVisualStudio.NET 2003ではashxファイルはサポートされておらず、インテリセンスなどは利用できませんが、ぜひこの記事を参考に活用していただければと思います。
参考資料
- 『ASP.NETでいってみよう』 松本美穂・百田昌馬 著、翔泳社、2005年3月(書籍:データベースの利用について)