web-dev-qa-db-ja.com

ASP.NET MVCでのHttpContext.Items

シングルトンパターンを使用する独自のApplicationContextクラスを実装しています。リクエストのすべての部分でアクセスできるため、インスタンスをHttpContext.Itemsに保存したいと思います。私はASP.NET MVCでのHttpContextの使用について読んでいますが、大きな問題の1つは、テストが複雑になることです。 HttpContext.Itemsのテスト可能性について調査してみましたが、見つけることができるのはSessionに関するものだけです。私が見つけた唯一のものの1つは、Wroxに関するProfessional ASP.NET 3.5 MVCブックのサンプルの章からのものです( pdfリンクはこちら )。 15ページでこれはこう言っています:

使用できないもの:HttpContext.Items
このセクションの上で、私たちはきれいになり、あなたに嘘をついたと言いました:HttpContextはASP.NETMVCとASP.NETWebフォームの間で共有されていません。この結果、HttpContext.Itemsコレクションを使用してデータのビットを格納および取得することはできません。

これは、コントローラーにリダイレクトすると、HttpHandlerがSystem.Web.Mvc.MvcHandlerになるためです。これは、HttpContextWrapperを使用して作成され、独自のHttpContext.Currentの定義があります。残念ながら、このハンドシェイク中、HttpContext.Itemsなどは転送されません。

結局のところ、見た目と音はほとんど同じですが、HttpContextタイプは同じではなく、この方法でデータを渡すことはできません。

今、私はこれをテストしようとしました、そして私が知る限り、RedirectToActionを使用して別のコントローラーにリダイレクトする場合、HttpContext.Itemsは残ります。これをテストするために、デフォルトのASP.NETMVCプロジェクトを使用しています。私がやったことは、このメソッドをGlobal.asax.csに追加することです。

protected void Application_BeginRequest()
{
    Context.Items["Test"] = "Hello World";
}

また、HomeController.csで、Indexメソッドを次のように変更しました。

public ActionResult Index()
{
    return RedirectToAction("About");
}

また、Aboutメソッドを次のように変更しました。

public ActionResult About()
{
    Response.Write(Convert.ToString(HttpContext.Items["Test"]));
    return View();
}

アプリケーションを実行すると、ページは/ Home/AboutとResponseに正しくリダイレ​​クトされます。global.asax.csに設定されている正しい「HelloWorld」文字列を書き込みます。

それで、「HttpContext.Itemsのようなものが転送されない」と言ったときに、本の意味が理解できないかのように思えますORこれは転送されますが、 HttpContext.Itemsを使用します。

HttpContext.Itemsを避けることをお勧めする場合、リクエストごとにリクエスト全体でオブジェクトを保存する別の方法はありますか?

33
Ryan Hoffman

あなたの質問はいくつかのことを尋ねていますが、項目1はあなたが探している答えだと思います。

  1. リクエストごとのキャッシュにContext.Itemsを使用しても問題ありませんか?はい。処理中、リクエストごと、Webファーム内のマシンごとが基準である場合、Context.Itemsはそれを提供します。

  2. Context.Itemsでテストするのは難しいですか?テスト容易性に関しては、ある種のインターフェースの背後にContext.Itemsを隠します。このようにして、Context.Itemsを直接参照することなく、ユニットテスト機能を利用できます。それ以外の場合、Context.Itemsについて何をテストする必要がありますか?フレームワークが値を保存および取得することは?コードをSystem.Webに無知にしておくと、幸せなキャンピングカーになります。

  3. Context.ItemsRedirectToActionを生き残りますか?いいえ。テストは無効です。すべてのWebリクエストで「Hello、world」が設定されており、テストは2つのWebリクエストにまたがっています。 1つ目は、インデックスアクションが呼び出されたときです。 2つ目は、RedirectToActionアクションが呼び出されたときです(HTTP 302です)。失敗させるには、Indexアクションに新しい値を設定し、Aboutアクションで保持されているかどうかを確認します。

38
Nick Swarr

TempDataディクショナリを使用します。これは主にアクションリダイレクト間にオブジェクトを格納するためのものです。

public ActionResult Index()
{
    TempData.Add("Test", "Hello world");
    return RedirectToAction("About");
}

public ActionResult About()
{
    ViewData["Test"] = TempData["Test"];
    return View();
}

次に、ビューの値を取得します。

<%=ViewData["Test"] %>
3
user434917

テストを行ったところ、TempDataは実際にはセッション状態を無効にした状態で爆発しました。私の唯一のアドバイスは、オブジェクト自体を一時データに格納するのではなく、提案されているように単純な型付きフィールドを格納することです。オブジェクトツリーをシリアル化していないので、プロセス外で実行することによるパフォーマンスへの影響はそれほど大きくありません。

1
andymeadows