無料で作るASP.NETでWebサイト(7)―アクセスカウンタ設置編(1)

前回は無料ホスティングサービスに申し込むまでを書いてみた。外部サーバ(本番環境)が利用可能になれば、ローカル(開発環境)で作成したコンテンツをサーバに転送し、そこで公開することができる。以前にも書いたように基本的にはこれで問題ないのだが、いろいろ試しているとそんなに簡単にいきそうにないことがわかった。特にデータベースはシステムに近い存在なので、セキュリティ上いろいろな制約を受けることが多い。そのあたりを、「アクセスカウンタ」を例にとって書いてみたい。

前の回へ:無料で作るASP.NETでWebサイト(6)
次の回へ:無料で作るASP.NETでWebサイト(8)

アクセスカウンタとは

アクセスカウンタは、Webアプリケーションではおなじみの機能である。たいていの場合は、HTMLページのimgタグにCGIへのリンクを埋め込むなどして、画像形式のカウンタを実現する。アクセスカウンタをどのように見せるかはここではあまり関係ないので、内部的にどのように実現するかということを書いていこう。

アクセスカウンタのオーソドックスな実現方法は、このような感じだ。

  1. あるページが表示される際にカウンタ用のプログラムがサーバ側で実行される。
  2. プログラムがカウント値を保存したファイルを読み込む。
  3. プログラムがカウントアップ後に書き戻す。
  4. 取得したカウント値をテキスト、画像へのリンクなどでページに埋め込む。

基本的にはこの手順で問題なくアクセスカウンタが実現できるが、アクセスが重なるとカウント値を保存したファイルが破損したり、CGIなどでプログラムが起動するのでパフォーマンスが悪い、という問題点は言われていた。そこで、せっかくデータベースが使えるのだから、データベースでアクセスカウンタを実現しよう、というわけだ。

データベースでアクセスカウンタを実現

データベースでアクセスカウンタを実現すると、こんなメリットがある。まずは、いくつでもアクセスカウンタを設置できること。トップページだけでなく、サイトのコンテンツの種類ごとにカウンタを設置すれば、どのコンテンツが人気なのか不人気なのかわかるだろう。また、データベースでカウンタ値を保持すれば、データベース側の排他処理によって、アクセスが重なっても破損する心配がない。さらに、データベースには「ストアドプロシージャ」という便利な仕組みがあるので、これを利用するとカウントアップなどの処理をデータベース側で自動で行わせ、Webページ側ではこれを読み出すだけでよくなり、パフォーマンスがアップする。さらに、カウントアップの処理を1箇所で記述できるなどメンテナンス性もよい。とにかく、いいところだらけに見えるのだ。難点は、データベースのオペレーションやプログラミングなど、最低限の知識を持っておかなければならないというところだろうか。

開発環境と本番環境

さて、ここでアクセスカウンタをデータベースに作っていく前に、重要なことを押さえておく必要がある。それは、「開発環境のデータベース」と「本番環境のデータベース」は別物だということである。つまり、開発環境でデータベースを作成し、アクセスカウンタのための仕組みを作っていったとしても、本番環境から開発環境のデータベースは(当然だが)利用できないし、開発環境のデータベースをそっくり本番環境に移せるとは限らない、ということである。今回のように無料ホスティングサービスの場合はデータベースの利用に大きな制限があるのが当然で、案の定今回は方法はひとつ、System.Data.SqlClientクラスを使い、ホスト名、データベース名、ログオン情報のみでアクセスするという方法しかなかった。よってデータベースファイルのアタッチなどはできないため、開発環境で作成したデータベースファイルをサーバに送っても無意味だ。

また、データベースの作成は本番環境に対してのみ行い、開発環境から本番環境のものを利用しようとしても、それは非常に危険であるし(開発中のバグでデータベースを壊してしまうこともあり得る)、開発中の操作をデータベースに反映させてしまうのも気持ち悪いし、そもそもデータベースサーバは外部からアクセスできないのが普通だ。この選択肢は、最初から存在しないのだ。

このため、データベースの設計やストアドプロシージャの作成などは、開発環境と本番環境でそれぞれに行う必要がある。また、データベースへのアクセス方法が異なるので、開発環境でテストしたWebページの内容を本番環境に転送する際、設定(この場合Web.config)を変更する必要がある。面倒といえば面倒だが、これ以外に適切な方法が見つからなかった。

データベースの設定(開発環境)

では、開発環境のデータベースにアクセスカウンタのための仕組みを作っていこう。VWD上でデータベースを操作するには、データベースエクスプローラが使える。データベースエクスプローラでデータベースファイルを1個作成し(とりあえずDatabase.dbf)、アクセスカウンタ用のテーブルCounterを作成する。フィールドは、ckey(varchar(50))とvalue(int)の2つを作成する。ckeyはカウンタを識別するための名前、valueがカウント値だ。これを作れば、カウンタの基礎部分は完成だ。

続けて、カウントアップのためのストアドプロシージャを作っていこう。ストアドプロシージャもデータベースエクスプローラで作成できる。CountUpという名前で、以下のように作成すればOKだ。

CREATE PROCEDURE CountUp
    @ckey VARCHAR(10)
AS
    IF EXISTS (SELECT * FROM Counter WHERE ckey = @ckey)
        BEGIN
            UPDATE Counter SET value = value+1 WHERE ckey = @ckey
        END
    ELSE
        BEGIN
            INSERT INTO Counter(ckey, value) VALUES(@ckey,1)
        END
    SELECT value FROM Counter WHERE ckey = @ckey

このストアドプロシージャは、@ckeyで指定されるカウンタ識別キーckeyが存在すればカウント値であるvalueを増やし、存在しなければ@ckeyを新たなカウンタ識別キーとしカウント値を1として新規作成するというものである。最後に、カウンタ値を取り出してプロシージャから返すようになっている。なお、一度作成すると冒頭のCREATEがALTERに変化するが、これは二度目からは置き換えになるのでこのようになっている。間違いと思ってCREATEに書き換えても二重作成でエラーになるので注意。これで、データベース側の準備は終わりである。説明は割愛するが、データベース単体でテストも可能だ。

Webページの作成(開発環境)

続けて、カウント値をページに反映させる仕組みを作ってみる。今回は単純化のために、カウント値をテキストでそのままページに埋め込むことにする。必要なのは、データベースに接続するためのSqlDataSourceサーバコントロールと、カウント値を書き込むLiteralサーバコントロールである。ページのLoadイベントでSqlDataSourceからカウント値を取り出し、LiteralのTextプロパティにその値を設定する。

最初に、ページに配置したSqlDataSourceサーバコントロールにプロパティを設定するのだが、データベースへの接続に必要な文字列(ConnectionString)をあらかじめ作っておこう。この文字列は、Web.configのconnectionStrings要素の中に記述する。ここに、以下のように要素を追加する。

    <add name="ConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient" />

これは、開発環境のSQL Server 2005 Express Editionを使うためのもので、本番環境では、違った記述にしなければならない。では、SqlDataSourceサーバコントロールにプロパティを設定しよう。

プロパティ 設定値
id SqlDataSource1(規定値)
ConnectionString ConnectionString
SelectCommandType StoredProcedure
SelectCommand CountUp
DataSourceMode DataReader

これで、コントロールを通じてデータベースにアクセスする準備が整った。あとは、ページのLoadイベントを記述するだけである。

            SqlDataSource1.SelectParameters.Clear();
            SqlDataSource1.SelectParameters.Add("ckey", "TOP");
            IDataReader ireader = (IDataReader)SqlDataSource1.Select(DataSourceSelectArguments.Empty);
            if (ireader.Read())
            {
                Literal1.Text = String.Format("{0:D5}", ireader["value"]);
            }

トップページなので、データベースのckeyフィールドには「TOP」を指定している。データベースからうまく読み込めれば、LiteralのTextプロパティに5桁に整形したカウント値を書き込む。これだけである。

ほかにカウンタが必要なら、「TOP」を変えて、それぞれページのLoadイベントに処理を記述していくだけだ。テキストのカウント値が地味と思うなら、自分でグラフィカルに改造してみてもいい。その場合には、Literalサーバコントロールでは無理なので、PlaceHolderサーバコントロール、Imageサーバコントロールなどを使い、数値を画像に置き換えていくなどの処理になる。

さて、ここまでは開発環境の作業である。開発環境で実行し、ページへのアクセスに伴いカウント値がアップしていけば、とりあえずは成功である。次に本番環境で動かすために、本番環境側でもテーブルの作成、ストアドプロシージャの作成を行う。ただしそれもちょっと長くなりそうなので、次回に回すことにする。

コメント