web-dev-qa-db-ja.com

HttpContext.Current.Applicationを使用して単純なデータを保存する

単純なオブジェクト(3つの文字列を含む)の小さなリストをASP.NETMVCアプリケーションに保存したいと思います。リストはデータベースから読み込まれ、サイトの管理領域でいくつかの値を編集することによって更新されることはめったにありません。

HttpContext.Current.Applicationを使って保存することを考えています。このようにして、Global.asaxにロードできます。

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    HttpContext.Current.Application["myObject"] = loadDataFromSql(); // returns my object
}

そして、必要に応じて、任意のコントローラーまたはビューから簡単に参照できます。次に、管理領域がupdateMyObjectコントローラーアクションを呼び出した場合、DBを更新して再度ロードし、HttpContext.Current.Application["myObject"]を置き換えることができます。

これを行うことの短所はありますか?私が達成しようとしていることにはうまくいくようですが、私がレイアウトした方法にいくつかの大きな欠点があると仮定して、これを行うためのより良い方法を誰かが知っていますか?

11
macca1

実際に行うことはCachingであり、外部ストレージ(データベースまたはファイルなど)への呼び出しを減らすので、それは素晴らしいことです。もちろん、トレードオフはメモリ使用量です。現在、ASP.NETを含むほとんどすべての最新のWebフレームワークには、ある種のキャッシュメカニズムが含まれています。それを使用するか、ある種のグローバル変数を使用します。

ASP.NETの組み込みのCacheオブジェクトにデータを格納すると、このメカニズムが実際にメモリ使用量をチェックし、いくつかのルールに従ってキャッシュされたデータを削除するため、いくつかの重要な利点があります。

ただし、キャッシュするデータがアプリケーション全体で集中的に使用され、そのサイズが大きすぎない(たとえば、1 MB未満)場合は、グローバル変数として格納することをお勧めします。

ASP.NETでは、グローバル変数は、質問で説明したようにApplicationオブジェクトを使用するか、内部/パブリッククラスにパブリック静的プロパティ/フィールドを書き込むことによって実現されます。

これが静的プロパティに対する私の解決策です。内部データを破損から保護するために、ロックオブジェクトを使用していることに注意してください。次のようになります。

public class WhateverClass
{
  private static object theLocker = new object();
  private static YourDataType theData;
  public static YourDataType TheData
  {
    get
    {
      lock (theLocker)
      {
        return theData;
      }
    }
    set
    {
      lock (theLocker)
      {
        theData = value;
      }
    }
  }
}

使用法は非常に簡単です:

初めて、Application_Startで:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    WhateverClass.TheData = loadDataFromSql();
}

任意のコントローラーで:

var myData = WhateverClass.TheData;

このパブリック静的プロパティは正確な型で明示的に宣言できるため、型の安全性があるため、このアプローチの方が優れています。さらに、この種のストレージはWebコンテキストに依存しないため、よりテスト可能です。

HTH!

32
Ron Klein

HttpContext.Current.Applicationは本質的に、従来のASPとの下位互換性のために必要な二日酔いです。これは本質的に、古典的なASPロックセマンティクス(Application.Lock/Application.UnLock)を備えた静的ハッシュテーブルです。

弱い型のハッシュテーブルとして、取得したオブジェクトをキャストする必要があります。

MyObject myObject = (MyObject) HttpContext.Current.Application["myObject"];

従来のASPからの移行ではないASP.NETアプリケーションでは、次のような他の標準的な.NETのものを使用することをお勧めします。

  • ロックが必要な場合に.NETロックセマンティクスを使用する静的フィールド(たとえば、要件に応じて、C#lockキーワードまたはReaderWriterLockSlimインスタンス):

    static MyObject myObject = LoadFromSql();

  • ASP.NETキャッシュ-有効期限、依存関係などを管理するための豊富な機能があります...

8
Joe

はい、HttpContext.Current.Applicationを使用すると、実行している作業に問題なく機能します。問題はありません。

HttpContext.Current.Applicationは、Webアプリケーションの.NET内の静的グローバルHttpApplicationStateオブジェクトへの単なる参照であり、Webアプリケーションごとに1つのグローバルインスタンスが存在する必要があります。そこにデータを格納することで、グローバル変数への高速でスレッドセーフなアクセスを提供します。この例のように、値を更新するときは必ずロックしてください。

System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["WebApplicationPath"] = MyWebApplicationPath;
System.Web.HttpContext.Current.Application.UnLock();

他の人が述べているように、App_Codeまたは他のフォルダに一連の静的クラスを作成し、そこにグローバル静的値とHttpContext.Current.Application値を格納して、値を安全にチェックしたり、データベースから更新するか、相互に更新して確認し、連携して動作します。私は通常、格納しているアプリケーション変数の管理と取得を支援するために静的グローバルクラスを作成します。このようにして、HttpApplicationStateクラスの状態ディクショナリとWebアプリケーションの静的オブジェクトの両方が連携して、グローバル値を共有および維持します。 (各静的クラスはワーカープロセスごとに割り当てられ、多くのWP Webサーバー/ Webではデフォルトで平均10 IISしたがって、静的タイプのデータは最小限に抑えてください。)

上記のサーバーファームの中には、アプリケーションの状態を共有しないものがあることに注意してください。これを管理する方法はたくさんあります。キャッシュが期限切れになったり、失敗したり、古くなったり、破損したりする可能性があるため、私はキャッシュのファンではありません。より簡単な解決策は、データベースとURLクエリ文字列を使用してサーバー間で通信し、状態を維持することです。幸運を!

5
Stokely

単一のWebサーバーにデプロイする場合、このアプローチは機能します。このような機能が必要な場合は、有効期限のオプションが増えるため、このためのキャッシュオブジェクトを検討してください。 (古いものではありますが、比較を参照してください、 ここ 。)

Webサーバーファームまたは同等のものにデプロイする場合は、 memcached または別のWebファームに適したキャッシュメカニズムを使用する必要があります。 ApplicationオブジェクトとCacheオブジェクトはどちらも、通常、単一のサーバーコンテキストにのみ存在します。ユーザーがセッション中に複数のWebサーバーにアクセスする可能性がある場合(およびキャッシュが同一である必要がある場合)、潜在的な各Webサーバーから表示できる共有キャッシュが必要になります。

どのパスを使用するかに関係なく、基になるデータが変更されるたびにキャッシュを無効化/リロードする必要があります。これは、アプリによって異なるカスタムコードです。

このアプローチはうまく機能し、物事をかなりスピードアップすることができますが、一見しただけでは理解できないほどの作業です...

3
Tahbaza