ASP.NET显示ModelState.AddModelError [英] ASP.NET display ModelState.AddModelError

查看:1579
本文介绍了ASP.NET显示ModelState.AddModelError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我这里此方法,这是一个登录方法,如果用户名和密码不正确被添加一个ModelError

  [HttpPost]
        公众的ActionResult登录(LoginClass型号,串RETURNURL)
        {            如果(ModelState.IsValid)
            {
                如果(Membership.ValidateUser(model.UserName,model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName,model.RememberMe);
                    如果(Url.IsLocalUrl(RETURNURL)及&放大器; ReturnUrl.Length→1&放大器;&放大器; ReturnUrl.StartsWith(/)
                        &功放;&安培; !ReturnUrl.StartsWith(//)及与放大器; !ReturnUrl.StartsWith(/ \\\\))
                    {
                       返回重定向(RETURNURL);
                    }
                    其他
                    {
                        返回RedirectToAction(指数,家);
                    }
                }
                其他
                {
                    ModelState.AddModelError(,提供的用户名或密码不正确);
                }
            }            返回RedirectToAction(指数,家);
        }

我的问题是如何显示ModelError我的看法Index.cshtml?


解决方案

  

...我将如何显示ModelError我的看法Index.cshtml?


显示错误消息

我最初做,你想重定向到主页的假设(的HomeController 行动首页)的基础上您的来电返回RedirectToAction(指数,家); 登录动作的底部。现在我想,也许这是你流了一个错误,你实际上是试图展示错误信息给用户,无需重定向,并且您只希望如果一切成功重定向。 如果是这样的话,然后只阅读这部分,并跳过有关如何在 RedirectToAction 通话持续模型状态休息。所有你需要做的就是调用查看而不是 RedirectToAction 中是否有故障。

  [HttpPost]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{
    如果(ModelState.IsValid)
    {
        如果(Membership.ValidateUser(model.UserName,model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName,model.RememberMe);
            如果(Url.IsLocalUrl(RETURNURL)及&放大器; ReturnUrl.Length→1&放大器;&放大器; ReturnUrl.StartsWith(/)
                &功放;&安培; !ReturnUrl.StartsWith(//)及与放大器; !ReturnUrl.StartsWith(/ \\\\))
            {
                返回重定向(RETURNURL);
            }
            其他
            {
                返回RedirectToAction(指数,家);
            }
        }
        其他
        {
            ModelState.AddModelError(,提供的用户名或密码不正确);
        }
    }    返回查看(模型); //追溯到与现有的模型和验证错误登录视图
    //返回RedirectToAction(指数,家);
}

Login.cshtml 某处包括以下

  @ Html.ValidationSummary()

与RedirectToAction工作

它不工作的原因是的ViewData ,其中包括验证消息,当您执行丢失的 RedirectToAction 。有几个选项的解决方案。


  1. 保留要么保持在的ViewData 横跨 RedirectToAction ,然后还原它。

  2. 仅坚持了的ModelState ,然后合并到的ModelState 曾经在<$ C指定的新动作$ C> RedirectToAction 已经执行。

坚持的ViewData

在大多数情况下,这工作得很好,但如果你重定向到行动(的在这种情况下,指数上的的HomeController 的),有可能会导致问题的自己的的ViewData 它所依赖的。

LoginController.cs

  //简化code只显示相关部分重现该问​​题/解决方案
[HttpPost]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{
    // ...一些其他的code
    ModelState.AddModelError(,提供的用户名或密码不正确);
    // ...一些其他的code    如果(!ModelState.IsValid)
        TempData的[的ViewData] = ViewData的;    返回RedirectToAction(指数,家);
}

HomeController.cs

 公众的ActionResult指数()
{
    如果(TempData的[的ViewData]!= NULL)
    {
        //恢复的ViewData
        ViewData的=(的ViewDataDictionary)的TempData [的ViewData];
    }    返回查看();
}

首页\\ Index.cshtml

  @ Html.ValidationSummary()

合并的ModelState

这是因为你定义将是我推荐的方法你怎么想这是一个自定义 ActionFilter 属性发生一次,然后应用,你想让它发生。你也可以直接把这个code到您的控制器,但将只要你需要做到这一点在多台控制器违反了DRY原则。

下面的方法是编写模型状态到的TempData 如果的TempData 不包含任何的ModelState键。如果已经有一个关键的present这意味着当前请求刚写完它,我们可以从中读取和合并,以我们现有的模型状态。这将prevent无意中覆盖的ViewState或ModelState中作为的ModelState现在合并了code。的我只能看到这个走错了,如果有多个 RedirectToActions 所有选择要写入的ModelState,但我不认为这是一个可能的情况。

ModelStateMergeFilterAttribute.cs

 公共类ModelStateMergeFilterAttribute:ActionFilterAttribute
{
    公共覆盖无效OnActionExecuted(ActionExecutedContext filterContext)
    {
        //写入临时数据,如果有ModelState中,但没有TempData的关键
        //这将允许它稍后重定向被合并
        如果(filterContext.Controller.TempData [的ModelState] == NULL和放大器;&安培;!filterContext.Controller.ViewData.ModelState = NULL)
        {
            filterContext.Controller.TempData [的ModelState] = filterContext.Controller.ViewData.ModelState;
        }
        //如果有TempData的(从previous行动)和它不一样的实例作为当前模型状态,则与现款车型进行合并
        否则,如果(filterContext.Controller.TempData [的ModelState] = NULL&放大器;!&安培; !filterContext.Controller.ViewData.ModelState.Equals(filterContext.Controller.TempData[\"ModelState\"]))
        {
            filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)filterContext.Controller.TempData[\"ModelState\"]);
        }
        base.OnActionExecuted(filterContext);
    }
}

LoginController.cs

  //简化了code只显示相关零件
[HttpPost]
[ModelStateMergeFilter]
公众的ActionResult登录(LoginClass型号,串RETURNURL)
{
    ModelState.AddModelError(,提供的用户名或密码不正确);
    返回RedirectToAction(指数,家);
}

HomeController.cs

  [ModelStateMergeFilter]
公众的ActionResult指数()
{
    返回查看();
}

首页\\ Index.cshtml

  @ Html.ValidationSummary()

参考

下面是一些参考资料也详细一些办法。我也依赖于一些从上面我的回答这些previous答案的投入。

I have this method here, which is a login method and if the username and password is incorrect a ModelError gets added.

 [HttpPost]
        public ActionResult Login(LoginClass model, string ReturnUrl)
        {

            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
                        && !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
                    {
                       return Redirect(ReturnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect");
                }
            }

            return RedirectToAction("Index", "Home");
        }

My question is how would I display the ModelError to my View Index.cshtml?

解决方案

... how would I display the ModelError to my View Index.cshtml?

Showing Error message

I initially made the assumption that you wanted to redirect to the home page (HomeController action Index) based on your call to return RedirectToAction("Index", "Home"); at the bottom of the Login action. Now I am thinking maybe this is a mistake in your flow and you are actually trying to show the error message to the user without redirecting and that you only want to redirect if everything succeeds. IF this is the case then just read this part and skip the rest about how to persist model state across RedirectToAction calls. All you need to do is call View instead of RedirectToAction if there is a failure.

[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
            if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
                && !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
            {
                return Redirect(ReturnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect");
        }
    }

    return View(model); // goes back to the login view with the existing model and validation error
    // return RedirectToAction("Index", "Home");
}

Login.cshtml include the following somewhere

@Html.ValidationSummary()

Working with RedirectToAction

The reason it is not working is the ViewData, which includes the validation messages, is lost when you execute the RedirectToAction. There are a couple of options for a solution.

  1. Keep either persist the ViewData across the RedirectToAction and then restore it.
  2. Only persist the ModelState and then merge it with the ModelState once the new action specified in the RedirectToAction has executed.

Persist ViewData

In most scenarios this works just fine but could cause problems if your redirected to action (in this case Index on the HomeController) has its own ViewData that it depends on.

LoginController.cs

// simplified code to just show the relevant parts to reproduce the problem/solution
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
    // ... some other code
    ModelState.AddModelError("", "The user name or password provided is incorrect");
    // ... some other code

    if (!ModelState.IsValid)
        TempData["ViewData"] = ViewData;

    return RedirectToAction("Index", "Home");
}

HomeController.cs

public ActionResult Index()
{
    if (TempData["ViewData"] != null)
    {
        // restore the ViewData
        ViewData = (ViewDataDictionary)TempData["ViewData"];
    }

    return View();
}

Home\Index.cshtml

@Html.ValidationSummary()

Merge the ModelState

This is would be my recommended approach because you define how you want this to happen once on a custom ActionFilter attribute and then apply where you want it to occur. You could also put this code directly into your controller but that would violate the DRY principle as soon as you need to do this on multiple controllers.

The approach here is to write the model state to the TempData if the TempData does not already contain a "ModelState" key. If there is already a key present that means that the current request has just written to it and we can read from it and merge that with our existing model state. This will prevent the code from unintentionally overwriting the ViewState or the ModelState as the ModelState is now merged. I can only see this going wrong if there are multiple RedirectToActions that all choose to write to the ModelState but I do not think this is a likely scenario.

ModelStateMergeFilterAttribute.cs

public class ModelStateMergeFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // write to the temp data if there is modelstate BUT there is no tempdata key
        // this will allow it to be merged later on redirect
        if (filterContext.Controller.TempData["ModelState"] == null && filterContext.Controller.ViewData.ModelState != null)
        {
            filterContext.Controller.TempData["ModelState"] = filterContext.Controller.ViewData.ModelState;
        }
        // if there is tempdata (from the previous action) AND its not the same instance as the current model state THEN merge it with the current model
        else if (filterContext.Controller.TempData["ModelState"] != null && !filterContext.Controller.ViewData.ModelState.Equals(filterContext.Controller.TempData["ModelState"]))
        {
            filterContext.Controller.ViewData.ModelState.Merge((ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);
        }
        base.OnActionExecuted(filterContext);
    }
}

LoginController.cs

// simplified the code to just show the relevant parts
[HttpPost]
[ModelStateMergeFilter]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
    ModelState.AddModelError("", "The user name or password provided is incorrect");
    return RedirectToAction("Index", "Home");
}

HomeController.cs

[ModelStateMergeFilter]
public ActionResult Index()
{
    return View();
}

Home\Index.cshtml

@Html.ValidationSummary()

References

Here are some references that also detail some of these approaches. I also relied on some of the input from these previous answers for my answer above.

这篇关于ASP.NET显示ModelState.AddModelError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆