読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC で確認画面を実装する(完全版)

初めに謝っておかないといけないことが。前に書いたこれ ASP.NET MVC で確認画面を表示させてみる - しばやん雑記 が全く動いてなかったんですよね(白目

なので、今回は確認画面を表示する完全版を作成したので、説明と使い方をつらつらと書いていきます。

まず、基本的な方針としては前回と変わりません。属性を指定するだけで規約に従って、確認画面のビューを表示したりしてくれます。早速 Confirm 属性の完全版のコードを見てもらいましょうか。

public class ConfirmAttribute : ActionFilterAttribute
{
    private const string SubmitButtonKey = "__SubmitButton";
    private const string ConfirmButtonKey = "__ConfirmButton";
    private const string BackButtonKey = "__BackButton";

    private const string ViewSuffix = "Confirm";

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var form = filterContext.HttpContext.Request.Form;

        var tempData = filterContext.Controller.TempData;

        var parameter = filterContext.ActionParameters.First();

        // 登録ボタンがクリックされた時
        if (form[SubmitButtonKey] != null)
        {
            // モデルデータをテンポラリから削除する
            tempData.Remove(parameter.Key);

            return;
        }

        // アクションの名前を取得
        var viewName = filterContext.ActionDescriptor.ActionName;

        // 確認ボタンがクリックされた時
        if (form[ConfirmButtonKey] != null)
        {
            // モデルの検証でエラーが発生しているか調べる
            if (!filterContext.Controller.ViewData.ModelState.IsValid)
            {
                // エラーが発生しているので何もしない
                return;
            }

            // 確認画面を表示するためにビュー名を変更
            viewName += ViewSuffix;

            // モデルデータをテンポラリに保存する
            tempData[parameter.Key] = parameter.Value;
        }

        // モデルデータをテンポラリから取得する
        var model = tempData.Peek(parameter.Key);

        // ビューを表示する
        filterContext.Result = new ViewResult
        {
            ViewName = viewName,
            ViewData = new ViewDataDictionary(model),
            TempData = tempData,
        };
    }
}

前回のよりはリファクタリングとかちょっとしたので見やすくなった気がします。そして今回は完全版ですので確認ボタンなどを生成するための HTML ヘルパーも用意しました。

public static class ConfirmExtensions
{
    public static MvcHtmlString SubmitButton(this HtmlHelper helper, string value)
    {
        var builder = new TagBuilder("input");

        builder.Attributes.Add("type", "submit");
        builder.Attributes.Add("name", "__SubmitButton");
        builder.Attributes.Add("value", value);

        return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
    }

    public static MvcHtmlString ConfirmButton(this HtmlHelper helper, string value)
    {
        var builder = new TagBuilder("input");

        builder.Attributes.Add("type", "submit");
        builder.Attributes.Add("name", "__ConfirmButton");
        builder.Attributes.Add("value", value);

        return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
    }

    public static MvcHtmlString BackButton(this HtmlHelper helper, string value)
    {
        var builder = new TagBuilder("input");

        builder.Attributes.Add("type", "submit");
        builder.Attributes.Add("name", "__BackButton");
        builder.Attributes.Add("value", value);

        return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
    }
}

Html.SubmitButton が登録ボタン、Html.ConfirmButton が確認ボタン、Html.BackButton が戻るボタンになってます。これをビューに仕込むだけなので非常に簡単ですよね。

そして、後は前回と同じコードで問題ないのですが、最後に非常に重要な設定を行う必要があります。とりあえず NuGet で Mvc3Futures をインストールしてください。Package Manager Console では

Install-Package Mvc3Futures

とタイプするだけでインストールできます。素晴らしき NuGet の世界。

インストールが終わったら Global.asax.cs の Application_Start に以下のコードを追記してください。

// using Microsoft.Web.Mvc; を忘れないように
ValueProviderFactories.Factories.Add(new TempDataValueProviderFactory());

これで確認画面が動作するようになります。今まで動いてなかった原因は TempData に入れた内容がモデルバインダでの対象にならないからです。ちなみにモデルバインダで自動的にバインディングされる内容は MVC 3 のデフォルトでは以下の通りです。

  • フォーム要素
  • クエリ文字列
  • ルートデータ
  • アップロードされたファイル

しかし MVC 3 Futures には SessionValueProviderFactory と TempDataValueProviderFactory が用意されているので、今回はこれを利用したというわけです。