1. ホーム
  2. asp.net-mvc-3

[解決済み】ViewBag、ViewData、TempDataについて

2022-04-09 08:57:46

質問

をどのような場合に使用するのか、どなたか教えてください。

  1. TempData
  2. ビューバッグ
  3. ビューデータ

コントローラ1に値を設定し、そのコントローラがコントローラ2にリダイレクトされ、コントローラ2がビューをレンダリングするという要件があります。

私はViewBagを使用しようとしましたが、値は私がコントローラ2に到達するまでに失われてしまいます。

使用するタイミングやメリット・デメリットを知ることができますか?

ありがとうございます。

解決方法は?

<ブロッククオート

1) TempData

リダイレクトのために生き残るデータを保存できるようにします。内部的にはSessionをバッキングストアとして使用し、リダイレクトが行われた後は自動的にデータが退避されます。パターンは以下の通りです。

public ActionResult Foo()
{
    // store something into the tempdata that will be available during a single redirect
    TempData["foo"] = "bar";

    // you should always redirect if you store something into TempData to
    // a controller action that will consume this data
    return RedirectToAction("bar");
}

public ActionResult Bar()
{
    var foo = TempData["foo"];
    ...
}

2)ViewBag、ViewData

コントローラのアクションに、対応するビューで使用するデータを格納できるようにします。これは、アクションがビューを返し、リダイレクトを行わないことを想定しています。現在のリクエストの間だけ生きています。

パターンは以下の通りです。

public ActionResult Foo()
{
    ViewBag.Foo = "bar";
    return View();
}

とビューに表示されます。

@ViewBag.Foo

またはViewDataを使用します。

public ActionResult Foo()
{
    ViewData["Foo"] = "bar";
    return View();
}

とビューに表示されます。

@ViewData["Foo"]

ViewBag は単なる動的なラッパーで ViewData で、ASP.NET MVC 3にのみ存在します。

とはいえ、この2つの構成は決して使うべきではないでしょう。ビューモデルと強く型付けされたビューを使用すべきです。つまり、正しいパターンは以下の通りです。

ビューモデル。

public class MyViewModel
{
    public string Foo { get; set; }
}

アクション

public Action Foo()
{
    var model = new MyViewModel { Foo = "bar" };
    return View(model);
}

強い型付けされたビュー。

@model MyViewModel
@Model.Foo


簡単な紹介の後、質問にお答えしましょう。

<ブロッククオート

私の要件は、コントローラ1に値を設定することです。 コントローラはControllerTwoにリダイレクトされ、Controller2がレンダリングします。 ビューを表示します。

public class OneController: Controller
{
    public ActionResult Index()
    {
        TempData["foo"] = "bar";
        return RedirectToAction("index", "two");
    }
}

public class TwoController: Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            Foo = TempData["foo"] as string
        };
        return View(model);
    }
}

と対応するビュー( ~/Views/Two/Index.cshtml ):

@model MyViewModel
@Html.DisplayFor(x => x.Foo)


TempDataの使用には欠点もあります。ユーザーがターゲットページでF5キーを押した場合、データが失われるからです。

個人的には、TempDataも使っていません。なぜなら、内部でセッションを使用しており、私のアプリケーションではセッションを無効にしているからです。私は、よりRESTfulな方法でこれを実現することを好みます。リダイレクトを行う最初のコントローラアクションで、データストアにオブジェクトを保存し、リダイレクト時に生成された一意のIDを使用します。そして、ターゲットアクションでは、このIDを使用して、最初に格納されたオブジェクトをフェッチバックします。

public class OneController: Controller
{
    public ActionResult Index()
    {
        var id = Repository.SaveData("foo");
        return RedirectToAction("index", "two", new { id = id });
    }
}

public class TwoController: Controller
{
    public ActionResult Index(string id)
    {
        var model = new MyViewModel
        {
            Foo = Repository.GetData(id)
        };
        return View(model);
    }
}

ビューはそのままです。