13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ASP.NET Core MVC で Post-Redirect-Get パターン(ポスト後のページ再読み込みで二重ポストされないようにする)

Last updated at Posted at 2019-10-14

Post Redirect Get パターン

フォームを送信(HTTPPost )後に、ページを再読み込みするとフォームのデータが二重送信されてしまいます。
送信後しばらくたってページ再読込して表示を最新にしたいときなどに起こりがちです。
image.png
ブラウザのリロードボタンを押すと...
image.png

ASP.NET Core MVC ではPOSTリクエストに対しビューを返していると上記の問題が起こります。

    [HttpPost] public IActionResult Edit(EditViewModel vm) {   
      if (ModelState.IsValid) {
        /** データベースへの登録処理とか */
      }
      return View();  // ビューをそのまま返している
    }

これはPOSTリクエストをGETリクエストにリダイレクトしてページを再表示することで回避できます。
そのため Post-Redirect-Get パターンと呼ばれます。

サンプルプロジェクト

Post-Redirect-Get パターン の適用前

DemoController.cs
using Microsoft.AspNetCore.Mvc;
using PostRedirectGet.ViewModels.Demo;

namespace PostRedirectGet.Controllers {
  public class DemoController : Controller {

    // 画面表示時に呼ばれる
    [HttpGet] public IActionResult Edit() => View();

    // フォームの送信で呼ばれる
    [HttpPost] public IActionResult Edit(EditViewModel vm) {   
      if (ModelState.IsValid) {
        /** データベースへの登録処理とか */
      }
      return View();
    }
  }
}
Edit.cshtml
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model PostRedirectGet.ViewModels.Demo.EditViewModel
@{ ViewData["Title"] = "Some Page"; }

<div class="text-center">
  <h1 class="display-4">Psot-Redirect-Get Pattern</h1>
  <form asp-controller="Demo" method="post">
    New Email:  <input asp-for="Email" />
    <button type="submit">Register</button>
  </form>
</div>
EditViewModel.cs
using System.ComponentModel.DataAnnotations;

namespace PostRedirectGet.ViewModels.Demo {
  public class EditViewModel {
    [Required, EmailAddress] public string Email { get; set; }
  }
}

Post-Redirect-Get パターンの適用後

画面表示時のHTTPGetへリダイレクトするだけです。

DemoController.cs
  public class DemoController : Controller {
+   // 初期表示時とフォーム送信後に呼ばれる
    [HttpGet] public IActionResult Edit() => View();

    [HttpPost] public IActionResult Edit(EditViewModel vm) {   
      if (ModelState.IsValid) {
        /** データベースへの登録処理とか */
      }
-     return View();
+     // [HttpGet] public IActionResult Edit() へリダイレクトする
+     return RedirectToAction(nameof(Edit));
    }
  }

これでフォーム送信後にページを更新しても二重送信されなくなりました。

備考

プロジェクト構成は下記のとおりです。

.
|-- Controllers
|   `-- DemoController.cs
|-- PostRedirectGet.csproj
|-- Program.cs
|-- Properties
|   `-- launchSettings.json
|-- Startup.cs
|-- ViewModels
|   `-- Demo
|       `-- EditViewModel.cs
|-- Views
|   `-- Demo
|       `-- Edit.cshtml
|-- appsettings.Development.json
|-- appsettings.json
|-- bin
|-- obj
`-- wwwroot

.NET Core SDK のバージョンは 3.0.100 、C# の言語バージョンは 8.0 で作業しました。

$ dotnet --version
3.0.100
13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?