次の方法で共有


アプリケーションの起動時にデータをキャッシュする (VB)

Scott Mitchellによる

PDF をダウンロードする

任意の Web アプリケーションでは、一部のデータが頻繁に使用され、一部のデータは頻繁に使用されなくなります。 ASP.NET アプリケーションのパフォーマンスは、頻繁に使用されるデータを事前に読み込むという手法で向上させることができます。 このチュートリアルでは、プロアクティブ読み込みの 1 つの方法を示します。これは、アプリケーションの起動時にキャッシュにデータを読み込む方法です。

イントロダクション

前の 2 つのチュートリアルでは、プレゼンテーション レイヤーとキャッシュ レイヤーのデータのキャッシュについて説明しました。 ObjectDataSource を使用したデータのキャッシュでは、ObjectDataSource のキャッシュ機能を使用してプレゼンテーション レイヤーにデータをキャッシュする方法について説明しました。 アーキテクチャ内のデータのキャッシュ では、新しい個別のキャッシュ 層でのキャッシュが調べられます。 どちらのチュートリアルでも、データ キャッシュの操作で リアクティブ読み込みを 使用しました。 リアクティブ読み込みでは、データが要求されるたびに、システムは最初にキャッシュ内にあるかどうかを確認します。 そうでない場合は、データベースなどの元のソースからデータを取得し、キャッシュに格納します。 リアクティブ読み込みの主な利点は、実装の容易さです。 その欠点の 1 つは、要求間でパフォーマンスが不均等になることです。 前のチュートリアルのキャッシュ 層を使用して製品情報を表示するページを想像してみてください。 このページが初めてアクセスされたとき、またはメモリ制約または指定された有効期限に達したためにキャッシュされたデータが削除された後に初めてアクセスした場合は、データベースからデータを取得する必要があります。 そのため、これらのユーザー要求は、キャッシュで処理できるユーザー要求よりも時間がかかります。

プロアクティブ読み込み では、キャッシュされたデータを必要な前に読み込むことで、要求全体のパフォーマンスを滑らかにする代替キャッシュ管理戦略が提供されます。 通常、プロアクティブ読み込みでは、基になるデータが定期的にチェックされるか、更新があったときに通知されるプロセスが使用されます。 このプロセスでは、キャッシュを最新の状態に保つように更新します。 プロアクティブ読み込みは、基になるデータが低速なデータベース接続、Web サービス、またはその他の特に遅いデータ ソースから取得される場合に特に便利です。 ただし、プロアクティブ読み込みのこのアプローチは、変更を確認してキャッシュを更新するプロセスを作成、管理、デプロイする必要があるため、実装が困難になります。

プロアクティブ読み込みのもう 1 つのフレーバーと、このチュートリアルで説明する種類は、アプリケーションの起動時にキャッシュにデータを読み込んでいます。 この方法は、データベース参照テーブルのレコードなどの静的データをキャッシュする場合に特に便利です。

プロアクティブ読み込みとリアクティブ読み込みの違い、および長所、短所、実装に関する推奨事項の一覧については、「.NET Framework アプリケーションのキャッシュ アーキテクチャ ガイド」の「キャッシュの内容の管理」セクションを参照してください。

手順 1: アプリケーションの起動時にキャッシュするデータを決定する

前の 2 つのチュートリアルで調べたリアクティブ読み込みを使用したキャッシュの例は、定期的に変更される可能性があり、生成に大きく時間がかかるわけではないデータに対して適切に機能します。 ただし、キャッシュされたデータが変更されない場合、リアクティブ読み込みによって使用される有効期限は余分です。 同様に、キャッシュされるデータの生成に非常に長い時間がかかる場合、要求でキャッシュが空であると見なされるユーザーは、基になるデータが取得されるまで長い待ち時間を保持する必要があります。 アプリケーションの起動時に生成するのに非常に長い時間がかかる静的データとデータをキャッシュすることを検討してください。

データベースには動的で頻繁に変化する値が多数ありますが、ほとんどの場合、静的データもかなり多く含まれています。 たとえば、事実上すべてのデータ モデルには、固定された選択肢のセットの特定の値を含む 1 つ以上の列があります。 Patients データベース テーブルには、英語、スペイン語、フランス語、ロシア語、日本語などの一連の値を持つPrimaryLanguage列が含まれる場合があります。 多くの場合、これらの種類の列は 参照テーブルを使用して実装されます。 Patients テーブルに英語またはフランス語の文字列を格納するのではなく、2 つ目のテーブルが作成されます。一般的には、一意の識別子と文字列の説明の 2 つの列と、使用可能な値ごとにレコードが含まれます。 PrimaryLanguage テーブルのPatients列には、対応する一意識別子が参照テーブルに格納されます。 図 1 では、患者の John Doe の主な言語は英語で、Ed Johnson s はロシア語です。

言語テーブルは、患者テーブルで使用される参照テーブルです

図 1: Languages テーブルは、 Patients テーブルで使用される参照テーブルです

新しい患者を編集または作成するためのユーザー インターフェイスには、 Languages テーブル内のレコードによって設定された使用可能な言語のドロップダウン リストが含まれます。 キャッシュを使用しない場合、このインターフェイスにアクセスするたびに、システムは Languages テーブルに対してクエリを実行する必要があります。 ルックアップ テーブルの値は変更される頻度が非常に低いため、これは無駄で不要です。

前のチュートリアルで調べたのと同じリアクティブ読み込み手法を使用して、 Languages データをキャッシュできます。 ただし、リアクティブ読み込みでは時間ベースの有効期限が使用されます。これは静的参照テーブル データには必要ありません。 リアクティブ読み込みを使用したキャッシュはキャッシュをまったく行うよりも優れていますが、アプリケーションの起動時に参照テーブルデータをキャッシュに事前に読み込むのが最善の方法です。

このチュートリアルでは、参照テーブル データとその他の静的な情報をキャッシュする方法について説明します。

手順 2: データをキャッシュするさまざまな方法を調べる

情報は、さまざまな方法を使用して ASP.NET アプリケーションにプログラムでキャッシュできます。 前のチュートリアルでデータ キャッシュを使用する方法を既に確認しました。 または、 静的メンバー または アプリケーションの状態を使用して、オブジェクトをプログラムでキャッシュすることもできます。

クラスを操作する場合は、通常、メンバーにアクセスする前に、クラスを最初にインスタンス化する必要があります。 たとえば、ビジネス ロジック レイヤーのいずれかのクラスからメソッドを呼び出すには、まずクラスのインスタンスを作成する必要があります。

Dim productsAPI As New ProductsBLL()
productsAPI.SomeMethod()
productsAPI.SomeProperty = "Hello, World!"

SomeMethod を呼び出したり、SomeProperty で作業したりする前に、まず、New キーワードを使用してクラスのインスタンスを作成する必要があります。 SomeMethodSomeProperty は、特定のインスタンスに関連付けられます。 これらのメンバーの有効期間は、関連付けられているオブジェクトの有効期間に関連付けられます。 一方、静的メンバーは、クラスのすべてのインスタンス間で共有される変数、プロパティ、およびメソッドであり、その結果、クラスの有効期間が限られます。 静的メンバーはキーワード Sharedで表されます。

静的メンバーに加えて、アプリケーションの状態を使用してデータをキャッシュできます。 各 ASP.NET アプリケーションは、アプリケーションのすべてのユーザーとページで共有される名前/値コレクションを保持します。 このコレクションにはHttpContext クラスApplication プロパティを使用してアクセスでき、次のように ASP.NET ページのコードビハインド クラスから使用できます。

Application("key") = value
Dim value As Object = Application("key")

データ キャッシュは、データをキャッシュするためのより豊富な API を提供し、時間と依存関係に基づく有効期限、キャッシュ項目の優先順位などのメカニズムを提供します。 静的メンバーとアプリケーションの状態では、このような機能はページ開発者が手動で追加する必要があります。 ただし、アプリケーションの起動時にアプリケーションの有効期間中にデータをキャッシュする場合、データ キャッシュの利点は大いにあります。 このチュートリアルでは、静的データをキャッシュするために 3 つの手法をすべて使用するコードについて説明します。

手順 3: テーブル データSuppliersキャッシュする

これまでに実装した Northwind データベース テーブルには、従来の参照テーブルは含まれていません。 DAL に実装されている 4 つの DataTable は、値が非静的であるすべてのモデル テーブルです。 このチュートリアルでは、DAL に新しい DataTable を追加し、新しいクラスとメソッドを BLL に追加する時間を費やすのではなく、 Suppliers テーブルのデータが静的であるふりをしましょう。 そのため、アプリケーションの起動時にこのデータをキャッシュできます。

まず、StaticCache.cs フォルダーに CL という名前の新しいクラスを作成します。

CL フォルダーに StaticCache.vb クラスを作成する

図 2: StaticCache.vb フォルダーにCL クラスを作成する

起動時にデータを適切なキャッシュ ストアに読み込むメソッドと、このキャッシュからデータを返すメソッドを追加する必要があります。

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Private Shared suppliers As Northwind.SuppliersDataTable = Nothing
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using a static member variable
        Dim suppliersBLL As New SuppliersBLL()
        suppliers = suppliersBLL.GetSuppliers()
    End Sub
    
    <DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return suppliers
    End Function
End Class

上記のコードでは、suppliers静的メンバー変数を使用して、SuppliersBLL メソッドから呼び出される GetSuppliers() クラスの LoadStaticCache() メソッドの結果を保持します。 LoadStaticCache() メソッドは、アプリケーションの起動時に呼び出されることを意図しています。 このデータがアプリケーションの起動時に読み込まれたら、サプライヤー データを操作する必要があるページは、 StaticCache クラスの GetSuppliers() メソッドを呼び出すことができます。 そのため、サプライヤーを取得するためのデータベースの呼び出しは、アプリケーションの開始時に 1 回だけ行われます。

キャッシュ ストアとして静的メンバー変数を使用する代わりに、アプリケーションの状態またはデータ キャッシュを使用することもできます。 次のコードは、アプリケーションの状態を使用するように再ツールされたクラスを示しています。

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using application state
        Dim suppliersBLL As New SuppliersBLL()
        HttpContext.Current.Application("key") = suppliers
    End Sub
    
    <DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return TryCast(HttpContext.Current.Application("key"), _
            Northwind.SuppliersDataTable)
    End Function
End Class

LoadStaticCache()では、サプライヤー情報はアプリケーション変数キーに格納されます。 Northwind.SuppliersDataTableから適切な型 (GetSuppliers()) として返されます。 アプリケーションの状態は、Application("key")を使用して ASP.NET ページの分離コード クラスでアクセスできますが、アーキテクチャでは、現在のHttpContext.Current.Application("key")を取得するためにHttpContextを使用する必要があります。

同様に、次のコードに示すように、データ キャッシュをキャッシュ ストアとして使用できます。

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using a static member variable
        Dim suppliersBLL As New SuppliersBLL()
        HttpRuntime.Cache.Insert("key", suppliers, Nothing, _
            Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, _
            CacheItemPriority.NotRemovable, Nothing)
    End Sub
    <System.ComponentModel.DataObjectMethodAttribute_
    (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return TryCast(HttpRuntime.Cache("key"), Northwind.SuppliersDataTable)
    End Function
End Class

時間ベースの有効期限なしで項目をデータ キャッシュに追加するには、 System.Web.Caching.Cache.NoAbsoluteExpirationSystem.Web.Caching.Cache.NoSlidingExpiration の値を入力パラメーターとして使用します。 キャッシュ項目のInsertを指定できるように、データ キャッシュのメソッドのこの特定のオーバーロードが選択されました。 優先順位は、使用可能なメモリが不足しているときにキャッシュからスカベンジする項目を決定するために使用されます。 ここでは、優先順位 NotRemovableを使用して、このキャッシュ項目が清掃されないようにします。

このチュートリアルのダウンロードでは、静的メンバー変数アプローチを使用して StaticCache クラスを実装します。 アプリケーションの状態とデータ キャッシュ手法のコードは、クラス ファイル内のコメントで使用できます。

手順 4: アプリケーションの起動時にコードを実行する

Web アプリケーションの起動時にコードを実行するには、 Global.asaxという名前の特別なファイルを作成する必要があります。 このファイルには、アプリケーション、セッション、および要求レベルのイベントのイベント ハンドラーを含めることができます。ここでは、アプリケーションの起動時に実行されるコードを追加できます。

Visual Studio のソリューション エクスプローラーで Web サイト プロジェクト名を右クリックし、[新しい項目の追加] を選択して、 Global.asax ファイルを Web アプリケーションのルート ディレクトリに追加します。 [新しい項目の追加] ダイアログ ボックスで、[グローバル アプリケーション クラス] 項目の種類を選択し、[追加] ボタンをクリックします。

プロジェクトに Global.asax ファイルが既にある場合、[新しい項目の追加] ダイアログ ボックスにグローバル アプリケーション クラス項目の種類は表示されません。

Global.asax ファイルを Web アプリケーションのルート ディレクトリに追加する

図 3: Global.asax ファイルを Web アプリケーションのルート ディレクトリに追加する (フルサイズの画像を表示する をクリックします)

既定の Global.asax ファイル テンプレートには、サーバー側の <script> タグ内に 5 つのメソッドが含まれています。

  • Application_Start は、Web アプリケーションが最初に起動したときに実行されます
  • Application_End アプリケーションのシャットダウン時に実行される
  • Application_Error ハンドルされない例外がアプリケーションに到達するたびに実行されます
  • Session_Start は、新しいセッションが作成されたときに実行されます
  • Session_End セッションが期限切れまたは破棄されたときに実行される

Application_Start イベント ハンドラーは、アプリケーションのライフ サイクル中に 1 回だけ呼び出されます。 アプリケーションは、ASP.NET リソースがアプリケーションから初めて要求されるときに起動し、アプリケーションが再起動されるまで実行を続けます。これは、 /Bin フォルダーの内容の変更、 Global.asaxの変更、 App_Code フォルダー内の内容の変更、 Web.config ファイルの変更などによって発生する可能性があります。 アプリケーションの ライフ サイクル の詳細については、「ASP.NET アプリケーション ライフ サイクルの概要」を参照してください。

これらのチュートリアルでは、 Application_Start メソッドにコードを追加するだけで済むので、他のコードは自由に削除してください。 Application_Startでは、StaticCache クラスの LoadStaticCache() メソッドを呼び出すだけで、サプライヤー情報が読み込まれ、キャッシュされます。

<%@ Application Language="VB" %>
<script runat="server">
    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        StaticCache.LoadStaticCache()
    End Sub
</script>

それがすべてです! アプリケーションの起動時に、 LoadStaticCache() メソッドは BLL からサプライヤー情報を取得し、静的メンバー変数 (または、 StaticCache クラスで使用したキャッシュ ストア) に格納します。 この動作を確認するには、 Application_Start メソッドにブレークポイントを設定し、アプリケーションを実行します。 ブレークポイントは、アプリケーションの起動時にヒットすることに注意してください。 ただし、後続の要求では、 Application_Start メソッドは実行されません。

ブレークポイントを使用して、Application_Start イベント ハンドラーが実行されていることを確認する

図 4: ブレークポイントを使用して、 Application_Start イベント ハンドラーが実行されていることを確認する (フルサイズの画像を表示する をクリックします)。

最初にデバッグを開始したときに Application_Start ブレークポイントにヒットしなかった場合は、アプリケーションが既に開始されているためです。 Global.asaxまたはWeb.configファイルを変更してアプリケーションを強制的に再起動してから、もう一度やり直してください。 これらのファイルの末尾に空白行を追加 (または削除) するだけで、アプリケーションをすばやく再起動できます。

手順 5: キャッシュされたデータを表示する

この時点で、 StaticCache クラスには、 GetSuppliers() メソッドを使用してアクセスできる、アプリケーションの起動時にキャッシュされたサプライヤー データのバージョンがあります。 プレゼンテーション レイヤーからこのデータを操作するには、ObjectDataSource を使用するか、ASP.NET ページの分離コード クラスから StaticCache クラスの GetSuppliers() メソッドをプログラムで呼び出すことができます。 ObjectDataSource コントロールと GridView コントロールを使用して、キャッシュされたサプライヤー情報を表示します。

まず、AtApplicationStartup.aspx フォルダーの Caching ページを開きます。 ツールボックスからデザイナーに GridView をドラッグし、その ID プロパティを Suppliersに設定します。 次に、GridView のスマート タグから、 SuppliersCachedDataSourceという名前の新しい ObjectDataSource を作成することを選択します。 StaticCache クラスの GetSuppliers() メソッドを使用するように ObjectDataSource を構成します。

StaticCache クラスを使用するように ObjectDataSource を構成する

図 5: StaticCache クラスを使用するように ObjectDataSource を構成する (フルサイズの画像を表示する をクリックします)

GetSuppliers() メソッドを使用して、キャッシュされたサプライヤー データを取得する

図 6: GetSuppliers() メソッドを使用して、キャッシュされたサプライヤー データを取得する (フルサイズの画像を表示する をクリックします)。

ウィザードが完了すると、Visual Studio によって、 SuppliersDataTable内の各データ フィールドに対して BoundFields が自動的に追加されます。 GridView と ObjectDataSource の宣言型マークアップは、次のようになります。

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="Address" HeaderText="Address" 
            SortExpression="Address" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
        <asp:BoundField DataField="Phone" HeaderText="Phone" 
            SortExpression="Phone" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="StaticCache" />

図 7 は、ブラウザーで表示したときのページを示しています。 出力は BLL s SuppliersBLL クラスからデータをプルした場合と同じですが、 StaticCache クラスを使用すると、アプリケーションの起動時にキャッシュされたサプライヤー データが返されます。 StaticCache クラスの GetSuppliers() メソッドにブレークポイントを設定して、この動作を確認できます。

キャッシュされたサプライヤー データが GridView に表示される

図 7: キャッシュされたサプライヤー データが GridView に表示されます (フルサイズの画像を表示する をクリックします)。

概要

ほとんどのデータ モデルには、通常、ルックアップ テーブルの形式で実装される、かなりの量の静的データが含まれています。 この情報は静的であるため、この情報を表示する必要があるたびにデータベースに継続的にアクセスする理由はありません。 さらに、静的な性質のため、データをキャッシュするときに有効期限が切れる必要はありません。 このチュートリアルでは、このようなデータを取得し、データ キャッシュ、アプリケーションの状態、および静的メンバー変数を使用してキャッシュする方法について説明しました。 この情報は、アプリケーションの起動時にキャッシュされ、アプリケーションの有効期間を通じてキャッシュに残ります。

このチュートリアルと過去 2 つのチュートリアルでは、アプリケーションの有効期間の間のデータのキャッシュと、時間ベースの有効期限の使用について説明しました。 ただし、データベース データをキャッシュする場合は、時間ベースの有効期限が理想的よりも短い場合があります。 キャッシュを定期的にフラッシュするのではなく、基になるデータベース データが変更されたときにキャッシュされた項目のみを削除するのが最適です。 この理想は、次のチュートリアルで説明する SQL キャッシュの依存関係を使用して可能です。

プログラミングに満足!

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジを使用しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・セルフ ASP.NET 24時間で2.0です。 彼には mitchell@4GuysFromRolla.comで連絡できます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、テレサ マーフィーと Zack Jones でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、mitchell@4GuysFromRolla.comにメッセージを送ってください。