Как я могу поддерживать ошибки ModelState при использовании RedirectToAction?

У меня есть код, который сохраняет билет в нашей системе. Если есть ошибка, это делает RedirectToAction. Проблема в том, что, похоже, у меня нет ошибок в новом действии. Как я могу это исправить?

 ModelState.AddModelError("_FORM", "Unable to save ticket");
 ModelState.AddModelError("_FORM", "Phone number was invalid.");
 ModelState.AddModelError("_FORM", "Lane number is required.");
 return RedirectToAction("CreateStep", "Ticket");

Я знаю, что некоторые предложили использовать TempData, но как я могу получить каждую ошибку из ModelState?

Спасибо.

Ответ 1

Шаблон PRG в порядке, но я сделал это:

Базовый контроллер:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    if (TempData["ModelState"] != null && !ModelState.Equals(TempData["ModelState"]))
        ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);

    base.OnActionExecuted(filterContext);
}

Действие (я использую xVal):

try
{
    user.Login();
    AuthenticationManager.SignIn(user);
}
catch (RulesException rex)
{
    // on bad login
    rex.AddModelStateErrors(ModelState, "user");
    TempData["ModelState"] = ModelState;
    return Redirect(Request.UrlReferrer.ToString());
}

Действие генерирует исключение, добавляет ModelState в TempData и перенаправляет обратно на реферер. Поскольку действие обнаружено, OnActionExecuted все еще выполняется, но первый раз вокруг ModelState совпадает с TempData [ "ModelState" ], поэтому вы не хотите сливаться с самим собой. Когда выполняется действие перенаправления, OnActionExecuted снова срабатывает. На этот раз, если что-нибудь в TempData [ "ModelState" ], оно сливается с этим действием ModelState.

Вы можете развернуть его на несколько моделей с помощью TempData [ "ModelState.user" ] = ModelState и затем слить каждый объект TempData, который начинается с ModelState.

Ответ 2

Я знаю, что эта ветка устарела, но этот блог о лучших рекомендациях ASP.NET содержит несколько отличных предложений.
# 13 на странице имеет дело с использованием 2 фильтров действий для сохранения и восстановления ModelState между переадресациями.

Это образец, который использует моя работа, и мне это нравится.

Здесь приведен упрощенный пример:

[ImportModelStateFromTempData]
public ActionResult Dashboard()
{
    return View();
}

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData]
public ActionResult Dashboard(string data)
{
    if (ValidateData(data))
    {
        try
        {
            _service.Submit(data);
        }
        catch (Exception e)
        {
            ModelState.AddModelError(ModelStateException, e);
        }
    }

    return RedirectToAction("Dashboard");
}

Ответ 4

Используйте коллекцию TempData []

Tempdata хранится от одного запроса до следующего, а затем его нет.

Ответ 5

Что я сделал, чтобы поддерживать свой ModelState независимо от того, куда я иду с переадресацией, следующее:

  • В вашей модели добавьте:

    public ModelStateDictionary modelstate { get; set; }
    
  • В конструкторе модели добавьте:

    this.modelstate = new System.Web.Mvc.ModelStateDictionary();
    
  • Пример сообщения с моей моделью под названием Models.ContactInformation:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult contact(Models.ContactInformation con)
    {
      if (string.IsNullOrEmpty(con.SelectedAgencySelectorType))
      {
        ModelState.AddModelError("", "You did not select an agency type.");
      }
    
      con.modelstate = ModelState;
      TempData["contact"] = con;
      if (!ModelState.IsValid) return RedirectToAction("contactinformation", "reports");
    
        //do stuff
    
        return RedirectToAction("contactinformation", "reports");
    }
    
  • Итак, теперь у ваших tempdata есть ваша модель и модель, как есть.

  • Следующее - это мое мнение, которое агностически относится к состоянию чего-либо, если у него нет чего-то. Здесь код:

    [HttpGet]
    public ActionResult contactinformation()
    {
        //try cast to model
        var m = new Models.ContactInformation();
        if (TempData["contact"] is Models.ContactInformation) m = (Models.ContactInformation)TempData["contact"];
    
        //restore modelstate if needed
        if (!m.modelstate.IsValid)
        {
            foreach (ModelState item in m.modelstate.Values)
            {
                foreach (ModelError err in item.Errors)
                {
                    ModelState.AddModelError("", err.ErrorMessage.ToString());
                }
            }
        }
    
        return View(m);
    }
    

Ответ 6

Я считаю, что вы теряете свое состояние модели, когда выполняете перенаправление. Возможно, вы могли бы переписать свою логику на что-то вроде:

public ActionResult Save()
{
  // your code...
  if(saveSucceeded)
  {
    return View("Saved");
  }
  else
  {
    return View("Create");
  }
}

И обычный способ получить сообщение об ошибке:

<%= Html.ValidationMessage("property_name") %>