フリーでそろう環境だけで ASP.NET アプリケーションを作成するためのチュートリアルです。ともかくフリーで作れるということに主眼を置いているため、プログラミングや言語についての解説は詳しく行っていません。感覚的に「ふ~ん、そんなことが出来るんだ。面白そうじゃん。」と思っていただくことを目的としています。もしこのページを読んで興味をもたれましたら、付属のドキュメントや市販の参考書などを手にとって見てください。
また、ASP.NET アプリケーションを Linux 上で動作させる方法についても解説します。
なお、このページでは言語として C# を使用しております。
まず、IIS で ASP.NET を実行するための設定を説明します。
最初に「プログラムの追加と削除」で「Windows コンポーネントの追加と削除」から IIS をインストールしてください。インストール後、とりあえず IIS が動いていることを確認するにはブラウザで「http://localhost/」と入力してください。正常に動作していればデフォルトのトップページが表示されます。
インストールが完了すると、C ドライブの下に「Inetput」というディレクトリが作成されす。そしてこの中の「wwwroot」というディレクトリが HTTP サーバーのルートとなります。この「wwwroot」の下に「sample」というディレクトリを作ってください。今回、そこで作業することにします。
次に「sample」ディレクトリ下で Web アプリケーションが動作するように IIS を設定します。「コントロール パネル」→「管理ツール」→「インターネット インフォメーション サービス」と選択し、IIS の設定画面を開いてください。設定画面が開いたら、コンピュータのアイコンを展開し、さらに「Web サイト」→「規定の Web サイト」と展開して「sample」ディレクトリのプロパティを開きます。.ここで、「アプリケーションの設定」にある「作成」ボタンを押して、プロパティを閉じます。
最後に、IIS で ASP.NET が使えるように .net framework SDK のツールで登録を行います。「C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322」のようなディレクトリ下にある「Aspnet_regiis.exe」を使って
>Aspnet_regiis.exe -i
IIS でとりあえず試してみたいという人はこのセクションは飛ばしてください。
前回、Linux で使用できる .net 環境として DotGNU を紹介しましたが、ASP.NET をやるには mono を使用することになります。DotGNU をインストールしている場合はアンインストールしておいてください。また、Apache と併用することを想定するので、Apache をインストールしておいてください。
私のテスト環境は RedHat9.0 です。まず、.の. から適切な RPM パッケージを拾ってきます。私は、必要なパッケージが一通りそろっている mono-all.zip をダウンロードし、全てインストールしました。ただし、依存関係により libpixman だけは Fedora Core 2.0 用のものを使用します。また、必要なパッケージとして.を要求されるかもしれませんので、その場合はインストールしておいてください。さらに libgal2 は. のアップデートを要求するかもしれません。その場合は.と一緒にアップデートしてください。
mono のインストールが完了したら mono の Apache 用モジュールをインストールします。先ほどの.の「Source Code」から「Apache Mono module 1.0 (mod_mono)」をダウンロードしてきます。これは ./configure、make、make install でインストールできます。configure は apache のインストール先ディレクトリを自動検出してくれるため、ライブラリは apache の modules ディレクトリ下にインストールされます。
続いて、Apache の httpd.conf を編集して mono のモジュールを登録します。httpd.conf に
LoadModule mono_module libexec/libmod_mono.so AddHandler mono .aspx .ascx .asax .ashx .config .cs .asmx
追記(04/10/04):今日現在、mono の最新バージョンは 1.0.2 ですが、この場合 mono-all では mod_mono が httpd を要求します。Web サーバーを rpm でなく別途インストールしている場合は mod_mono を除外し、mod_mono だけ別途ソースからインストールするようにします。また、mod_mono のモジュール名が「libmod_mono.so」ではなく「mod_mono.so」になっています。
次に mono 用の設定ファイルを作成します。場所はどこでもかまいませんが、ファイル名は「filename.webapp」のように拡張子を「.webapp」とします。このファイルへ
<web-application>
<name>sample</name>
<vpath>/sample</vpath>
<path>/www/sample/</path>
<vhost>www.parof.jp</vhost>
<vport>80</vport>
</web-application>
最後に mono を起動します。
# mono /usr/bin/mod-mono-server.exe --appconfigdir [appconfigdir] --nonstop &
# chmod 666 /tmp/mod_mono_server
これで mono で ASP.NET を利用する準備が整いました。ただ、実際に ASP.NET を使用してみると、変にキャッシュが働いて再コンパイルした結果が反映されないことがあります。動作がおかしいと思ったら mono を再起動してみるとよいでしょう。
ASP.NET プログラムは「デザインファイル(HTML)」「コードファイル(ソースファイル)」「アセンブリファイル(DLL)」によって構成されます。ここではデザインファイルを「Main.aspx」、コードファイルを「Main.aspx.cs」、アセンブリファイルを「Main.dll」として話を進めます。
ブラウザで aspx ファイルを呼び出すと、
1. コードファイル内(実際にはアセンブリファイル内)のメインとなる クラスが aspx ファイル全体を表すオブジェクトとして作成される。 2. コードファイル内の Load イベントに対応するイベントハンドラが 呼び出され、aspx ページの初期化を行う。 3. コントロールなどのイベントによる呼び出しであれば対応するイベント ハンドラを呼び出す。 4. HTML に変換され、ブラウザへ出力される。
このとき、aspx.cs のオブジェクトをいじると出力結果を操作できるという仕組みです。
また、aspx 内のボタンやブロック要素タグは System.Web.UI.WebControls.WebControl の派生クラスや System.Web.UI.HtmlControls.HtmlGenericControl クラスのオブジェクトとして表されます。イメージとしては
Page クラス ↑ aspx.cs 内のクラス メンバ:aspx 内のボタンなどのオブジェクト メンバ:aspx 内のtable div span などの要素
最も簡単なプログラムとして、ボタンを押すと文字が変化するというプログラムを作成してみます。なお、作成するファイルはいずれも UTF-8 で保存するとよいでしょう。これは Windows 上と Linux 上とで文字コードに起因する問題がおきないようにするためです。
aspx ファイルは基本的に HTML を記述します。
<%@ Page language="c#" AutoEventWireup="false" Inherits="sample.Main"%>
<html>
<head>
</head>
<body>
<form id="form" method="post" runat="server">
<asp:Button id="btn" runat="server" Text="ボタン"/>
<div id="block" runat="server">
<div id="label" runat="server"/>
</div>
</form>
</body>
</html>
Page ディレクティブは「<% Page」で始まり、「langueage」で言語を指定し、「Inherits」で aspx.cs 内のクラスを指定しています。「Inherits」での指定は「[aspx.cs 内の名前空間].[aspx.cs 内のメインとなるクラス]」となります。「AutoEventWireup」を true にすると aspx.cs 内で Load イベントのハンドラを登録しなくても自動的に「Page_Init」メソッドと「Page_Load」メソッドが呼ばれるようになりますが、今回は理解を深めるために false としておきます。
要素をオブジェクトとして扱うには2種類の方法があります。一つは .net framework で用意されたクラスのオブジェクトとして扱う方法で、例えば「<asp:Button」タグです。これは System.Web.UI.WebControls.Button であることを表しています。もう一つの方法は普通の HTML を System.Web.UI.HtmlControls.HtmlGenericControl として扱う方法です。これは HTML タグをそのまま使用します。いずれの方法も一意な id 属性を割り振ります。この属性名が aspx.cs 内での変数名になります。また、runat 属性で server と指定する必要があります。ここではボタンオブジェクトとして btn を、ブロック要素のオブジェクトとして block と label を用意しました。
次に、aspx に対応した aspx.cs ファイルを作成します。内容は以下のとおりです。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace sample {
public class Main : System.Web.UI.Page {
protected Button btn;
protected HtmlGenericControl block;
protected HtmlGenericControl label;
public Main() {
this.Load += new EventHandler(Page_Load);
}
private void Page_Load(object sender, EventArgs e) {
label.InnerText = "Hello";
btn.Click += new EventHandler(Clicked_Hello);
}
private void Clicked_Hello(object sender, EventArgs e) {
label.InnerText += " World";
}
}
}
まず、最初の using により ASP.NET で使いそうな一般的な名前空間を用意しておきます。なお、ここにあげた名前空間は Visual Studio .NET のプロジェクトとして作成した際に自動生成されたものを拝借してたものです。
今回、sample という名前空間を作成し、その中に Main というメインになるクラスを作成することにします。この Main は aspx のページを表すクラス Page を継承してます。
メンバ変数として、aspx ファイルで用意したオブジェクトを宣言します。それぞれ対応するクラスの変数として宣言します。変数名は id 属性で指定した値にあわせます。今回 form は使用しないので宣言しません。(block は後ほど使います。)
コンストラクタで、ページが読み込まれたときに発生する Load イベントに対してイベントハンドラ Page_Load を設定しています。(なお Visual Studio .NET のプロジェクトとして作成した場合、コンストラクタの代わりに.のようなコードが生成されます。
#region Web フォーム デザイナで生成されたコード
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: この呼び出しは、ASP.NET Web フォーム デザイナで必要です。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
この Page_Load が事実上の初期化処理になります。ここでは btn オブジェクトのボタンが押されたことを表す Click イベントに対してイベントハンドラ Hello_Click を設定しています。また label オブジェクト(div 要素)のテキストに「Hello」を設定しています。
Clicked_Hello では label のテキストに「 World」を付加して「Hello World」となるようにしています。
aspx ファイルと aspx.cs ファイルが用意できたらコンパイルして実行してみることにしましょう。ただし、コンパイルでは実行可能ファイルではなく DLL 形式のアセンブリファイルを作成します。また、この DLL ファイルは bin ディレクトリの中に格納します。そのため、bin ディレクトリをあらかじめ作成して置いてください。
コンパイルは
>csc /t:library /out:bin\Main.dll Main.aspx.cs
これで用意が出来ました。あとはブラウザから「http://localhost/sample/Main.aspx」のようにしてアクセスするだけです。
さて、上述のプログラムを実行してみて何かおかしい点に気付かれた方がいるかもしれません。このプログラムの内容からすれば、ボタンを複数回押せば表示が「Hello World」「Hello World World」「Hello World World World」のように「World」が増えていきそうなのに、そうはなりません。
これは、プログラムが呼ばれるたびに Page_Load が実行され、label のテキストが「Hello」に初期化されてしまうためです。なぜこのようなことになってしまうのでしょうか。それは考えてみれば単純な話で、一度ブラウザに表示されたものはそれだけで一枚のページとして完結しているからです。従って、ボタンを押すなどのアクションが行われた場合には再び新しいページとしてプログラムが実行されるため Page_Load によって初期化しなければならないのです。
同様に次のようなケースを考えてください。
protected void Clicked_Hello(object sender, EventArgs e) {
Button btn2 = new Button();
btn2.ID = "btn2";
btn2.Text = "ステップ2";
btn2.Click += new EventHandler(Clicked_Step2);
block.Controls.Add(btn2);
}
protected void Clicked_Step2(object sender, EventArgs e) {
label.InnerText += " World";
block.Controls.Remove(block.FindControl("btn2"));
}
さて、ここで期待するのは
1. btn ボタンを押す。 2. block の位置に btn2 ボタンが追加される。 3. btn2 ボタンを押す。 4. label のボタンが削除され「Hello World」と表示される。
これらの問題を回避するには Session により現在の状態を管理し、Page_Load で適切な処理を行う必要があります。まず期待通りの動作を行う、修正された aspx.cs ファイルを示します。
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace sample {
public class Main : System.Web.UI.Page {
protected Button btn;
protected HtmlGenericControl block;
protected HtmlGenericControl label;
public Main() {
this.Load += new EventHandler(Page_Load);
}
private void Page_Load(object sender, EventArgs e) {
String str;
if((str = (String)Session["label"]) == null){
str = "Hello";
Session["label"] = str;
}
label.InnerText = str;
Button btn2;
if((btn2 = (Button)Session["btn2"]) != null){
btn2.Click += new EventHandler(Clicked_Step2);
block.Controls.Add(btn2);
}
btn.Click += new EventHandler(Clicked_Hello);
}
private void Clicked_Hello(object sender, EventArgs e) {
Button btn2 = new Button();
btn2.ID = "btn2";
btn2.Text = "ステップ2";
btn2.Click += new EventHandler(Clicked_Step2);
block.Controls.Add(btn2);
Session["btn2"] = btn2;
}
private void Clicked_Step2(object sender, EventArgs e) {
block.Controls.Clear();
label.InnerText += " World";
block.Controls.Add(label);
Session.Remove("btn2");
Session["label"] = label.InnerText;
}
}
}
先に Click_Hello メソッドの下の方を見てください。Session というプロパティを操作しています。この Session は Web アプリーケーションにアクセスしている間のセッション全体にわたって利用できる情報の、辞書型(キーと値のペアのリスト)コンテナです。ここで「btn2」というキーで Button オブジェクト btn2 を保存しています。
次に Clicked_Step2 メソッドの下の方を見てください。Session に対して「label」というキーで label のテキストを保存しています。
では Page_Load メソッドを見てください。まず、Session の「label」キーを調べます。このキーが無ければ、初期値として「Hello」を設定します。このキーが存在するなら、その値を使用します。次に Session の「btn2」キーを調べます。このキーが存在するなら、その値(Button)を btn2 として block に追加します。このとき、イベントハンドラを改めて設定しなおしていることに注意してください (*1) 。こうすることにより、文字列が保存され、また btn2 がイベントを発生させた後の呼び出しでも Page_Load で btn2 が作成されるため、イベントハンドラが正しく呼び出されます。
上の例では Session にはオブジェクトも保存できる点、イベントハンドラは再設定する必要がある点を示すために Session へ「btn2」として Button オブジェクトを保存しましたが、あるいは「btn2」キーに対して Button オブジェクトを保存するのではなく、これをフラグのかわりに使用し、「btn2」の値が「true」なら Page_Load の中で新しく btn2 オブジェクトを作る、というふうにしてもよいでしょう。
なお、Clicked_Step2 メソッドは
label.InnerText += " World";
block.Controls.Remove(block.FindControl("btn2"));
Session.Remove("btn2");
Session["label"] = label.InnerText;
今回、情報を保存する手段として Session を使いましたが、他にも主にコントロールの状態(チェックボックスやリストボックスなどの状態)を保存する ViewState プロパティ、HTTP リクエストを処理する Request プロパティ HTTP レスポンスを処理する Response プロパティがあります。これらをうまく利用することでもアプリケーションを制御することが出来るでしょう。
足早ではありますが、ASP.NET の概要を分かっていただけたでしょうか。私自身、手探り状態で試したため至らぬ点が多々あるかとは思いますが、Java 以外でも Web アプリケーションの開発が出来るということをご理解いただき、また ASP.NET に興味を持ってみてもらえればと思います。