C# 使用 RedirectToAction 时如何维护 ModelState 错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/658747/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:13:03  来源:igfitidea点击:

How do I maintain ModelState errors when using RedirectToAction?

c#asp.netasp.net-mvc

提问by Mike Roosa

I have some code that saves a ticket in our system. If there is an error it does a RedirectToAction. The problem is that I don't seem to have my errors in the new action. How can I fix this?

我有一些代码可以在我们的系统中保存一张票。如果有错误,它会执行 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");

I know some have suggested using TempData, but how would I get each error out of the ModelState?

我知道有些人建议使用 TempData,但是我如何从 ModelState 中获取每个错误?

Thanks.

谢谢。

回答by AndreasN

Use the TempData[] Collection

使用 TempData[] 集合

The tempdata is stored from one request to the next, then its gone.

临时数据从一个请求存储到下一个请求,然后消失了。

回答by marc.d

this blog post describes how you could implement the PRG-Pattern in MVC http://blog.simonlovely.com/archive/2008/11/26/post-redirect-get-pattern-in-mvc.aspx

这篇博文描述了如何在 MVC 中实现 PRG-Pattern http://blog.simonlovely.com/archive/2008/11/26/post-redirect-get-pattern-in-mvc.aspx

hth

回答by marc.d

The PRG pattern is ok, but I did this:

PRG 模式没问题,但我这样做了:

Base controller:

基础控制器:

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

    base.OnActionExecuted(filterContext);
}

Action (I'm using xVal):

操作(我正在使用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());
}

The action throws an exception, adds the ModelState to TempData and redirects back to the referrer. Since the action is caught, OnActionExecuted is still executed, but the first time around the ModelState is the same as TempData["ModelState"], so you don't want to merge with yourself. When the redirect action is executed, OnActionExecuted fires again. This time, if there's anything in TempData["ModelState"], it merges with this action's ModelState.

该操作引发异常,将 ModelState 添加到 TempData 并重定向回引用者。由于action被抓到了,OnActionExecuted还是被执行了,但是第一次绕ModelState和TempData["ModelState"]是一样的,所以不想和自己合并。当执行重定向操作时,OnActionExecuted 再次触发。这一次,如果 TempData["ModelState"] 中有任何内容,它将与此操作的 ModelState 合并。

You could expand it to multiple models by using TempData["ModelState.user"] = ModelState and then merging every TempData object that starts with ModelState.

您可以通过使用 TempData["ModelState.user"] = ModelState 然后合并每个以 ModelState 开头的 TempData 对象,将其扩展为多个模型。

回答by Scott Rippey

I know this thread is old, but this blog about ASP.NET Best Practiceshas some excellent suggestions.
#13 on the page deals with using 2 Action filters to save and restore ModelStatebetween redirects.

我知道这个帖子很旧,但是这个关于 ASP.NET 最佳实践的博客有一些很好的建议。
页面上的 #13 处理使用 2 个操作过滤器ModelState在重定向之间保存和恢复。

This is the pattern that my work uses, and I love it.

这是我的作品使用的模式,我喜欢它。

Here's the simplified example:

这是一个简化的例子:

[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");
}

回答by Rudy Hinojosa

What I did to maintain my ModelState no matter where I go with redirects is the following:

无论我在哪里使用重定向,我都为维护我的 ModelState 所做的如下:

  1. In your model, add:

    public ModelStateDictionary modelstate { get; set; }
    
  2. In your model's constructor, add:

    this.modelstate = new System.Web.Mvc.ModelStateDictionary();
    
  3. Sample Post with my model called 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");
    }
    
  4. So now your tempdata has your model and modelstate as is.

  5. The following is my view that is agnostic to the state of anything, unless it has something. Here's the code:

    [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);
    }
    
  1. 在您的模型中,添加:

    public ModelStateDictionary modelstate { get; set; }
    
  2. 在模型的构造函数中,添加:

    this.modelstate = new System.Web.Mvc.ModelStateDictionary();
    
  3. 我的模型名为 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");
    }
    
  4. 所以现在你的临时数据有你的模型和模型状态。

  5. 以下是我对任何事物状态不可知的观点,除非它具有某些东西。这是代码:

    [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);
    }