1. ホーム
  2. c#

C# ASP.NET MVC 前のページに戻る

2023-08-29 05:55:01

質問

私のコントローラには、編集が成功したときにトップレベルのリスト(「インデックス」)にリダイレクトする基本的なEditメソッドがあります。MVC scaffoldingの後の標準的な動作です。

私はこのEditメソッドを、前のページ(Indexではない)にリダイレクトするように変更しようとしています。 私のEditメソッドはデフォルトでマップされた入力パラメータ「id」を使用していなかったので、まず、前のURLを渡すためにそれを使用してみました。

Editの "get "メソッドで、この行を使って前のURLを取得すると、うまくいきました。

ViewBag.ReturnUrl = Request.UrlReferrer;

そして、この戻り値のURLを、formタグを使って、Editの「post」メソッドに次のように送りました。

@using (Html.BeginForm(new { id = ViewBag.ReturnUrl }))

さて、ここで歯車が狂ってしまいました。 idパラメータから解析されたURLを正しく取得することができなかったのです。

*** 最新情報:解決済み ** *

Garry の例を参考に、パラメータを "id" から "returnUrl" に変更し、パラメータを渡すために (form タグの代わりに) hidden フィールドを使用しています。 教訓です。id"パラメータは、意図したとおりに使用し、シンプルに保つこと。 これでうまくいきました。 以下は、更新したコードとそのメモです。

まず、最初に行ったように Request.UrlReferrer を使用して前の URL を取得します。

    //
    // GET: /Question/Edit/5

    public ActionResult Edit(int id)
    {
        Question question = db.Questions.Find(id);
        ViewBag.DomainId = new SelectList(db.Domains, "DomainId", "Name", question.DomainId);
        ViewBag.Answers = db.Questions
                            .AsEnumerable()
                            .Select(d => new SelectListItem
                            {
                                Text = d.Text,
                                Value = d.QuestionId.ToString(),
                                Selected = question.QuestionId == d.QuestionId
                            });
        // Grab the previous URL and add it to the Model using ViewData or ViewBag
        ViewBag.returnUrl = Request.UrlReferrer;
        ViewBag.ExamId = db.Domains.Find(question.DomainId).ExamId;
        ViewBag.IndexByQuestion = string.Format("IndexByQuestion/{0}", question.QuestionId);
        return View(question);
    }

で、フォームの隠しフィールドを使ってモデルから[HttpPost]メソッドにreturnUrlパラメータを渡しています。

@using (Html.BeginForm())
{
    <input type="hidden" name="returnUrl" value="@ViewBag.returnUrl" />
    ...

HttpPost]メソッドで、hiddenフィールドからパラメータを取り出し、そこにRedirectする...。

    //
    // POST: /Question/Edit/5

    [HttpPost]
    public ActionResult Edit(Question question, string returnUrl) // Add parameter
    {
        int ExamId = db.Domains.Find(question.DomainId).ExamId;
        if (ModelState.IsValid)
        {
            db.Entry(question).State = EntityState.Modified;
            db.SaveChanges();
            //return RedirectToAction("Index");
            return Redirect(returnUrl);
        }
        ViewBag.DomainId = new SelectList(db.Domains, "DomainId", "Name", question.DomainId);
        return View(question);
    }

どのように解決するのですか?

編集に失敗したときに編集ページを再表示したい、そのためにリダイレクトを使っている、と仮定しています(間違っていたらご指摘ください)。

ユーザーをリダイレクトしようとするよりも、ビューを再び返す方がうまくいくかもしれません。この方法では、エラーも出力するためにModelStateを使用することができます。

編集してください。

フィードバックに基づき更新しました。 以前のURLをviewModelに置き、それをhiddenフィールドに追加し、編集を保存するアクションで再び使用することができます。

例えば

public ActionResult Index()
{
    return View();
}

[HttpGet] // This isn't required
public ActionResult Edit(int id)
{
   // load object and return in view
   ViewModel viewModel = Load(id);

   // get the previous url and store it with view model
   viewModel.PreviousUrl = System.Web.HttpContext.Current.Request.UrlReferrer;

   return View(viewModel);
}

[HttpPost]
public ActionResult Edit(ViewModel viewModel)
{
   // Attempt to save the posted object if it works, return index if not return the Edit view again

   bool success = Save(viewModel);
   if (success)
   {
       return Redirect(viewModel.PreviousUrl);
   }
   else
   {
      ModelState.AddModelError("There was an error");
      return View(viewModel);
   }
}

ビューの BeginForm メソッドもこの戻り値の URL を使う必要はないので、大丈夫でしょう。

@model ViewModel

@using (Html.BeginForm())
{
    ...
    <input type="hidden" name="PreviousUrl" value="@Model.PreviousUrl" />
}

フォームアクションが不正なURLに投稿されていることに戻ります。これは、'id'パラメータとしてURLを渡しているため、ルーティングが自動的にURLのリターンパスをフォーマットしてしまうためです。

これは、フォームがコントローラアクションに投稿され、編集を保存する方法を知らないため、うまくいきません。 まず保存アクションに投稿し、その中でリダイレクトを処理する必要があります。