Asp.net MVC ModelState.Clear

Mr *_*rok 114 asp.net-mvc post-redirect-get modelstate

任何人都可以给我一个关于ModelState在Asp.net MVC中的角色的简洁定义(或者链接到一个).特别是我需要知道在什么情况下打电话是必要的或可取的ModelState.Clear().

有点开放了 ......对不起,我想如果告诉你我在做什么可能会有所帮助:

我在一个名为"Page"的控制器上有一个Edit of Action.当我第一次看到表单更改页面的详细信息时,所有内容都很好地加载(绑定到"MyCmsPage"对象).然后,我单击一个按钮,为MyCmsPage对象的某个字段(MyCmsPage.SeoTitle)生成一个值.它生成正常并更新对象,然后我返回动作结果与新修改的页面对象,并期望相关的文本框(使用渲染<%= Html.TextBox("seoTitle", page.SeoTitle)%>)更新...但是它显示了加载的旧模型的值.

我通过使用来解决它,ModelState.Clear()但我需要知道它为什么/如何工作所以我不只是盲目地做.

的PageController:

[AcceptVerbs("POST")]
public ActionResult Edit(MyCmsPage page, string submitButton)
{
    // add the seoTitle to the current page object
    page.GenerateSeoTitle();

    // why must I do this?
    ModelState.Clear();

    // return the modified page object
     return View(page);
 }
Run Code Online (Sandbox Code Playgroud)

ASPX:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyCmsPage>" %>
....
        <div class="c">
            <label for="seoTitle">
                Seo Title</label>
            <%= Html.TextBox("seoTitle", page.SeoTitle)%>
            <input type="submit" value="Generate Seo Title" name="submitButton" />
        </div>
Run Code Online (Sandbox Code Playgroud)

Tim*_*ott 134

我认为是MVC中的一个错误.我今天花了几个小时努力解决这个问题.

鉴于这种:

public ViewResult SomeAction(SomeModel model) 
{
    model.SomeString = "some value";
    return View(model); 
}
Run Code Online (Sandbox Code Playgroud)

视图使用原始模型呈现,忽略更改.所以我想,也许它不喜欢我使用相同的模型,所以我尝试这样:

public ViewResult SomeAction(SomeModel model) 
{
    var newModel = new SomeModel { SomeString = "some value" };
    return View(newModel); 
}
Run Code Online (Sandbox Code Playgroud)

并且视图仍然使用原始模型呈现.奇怪的是,当我在视图中放置断点并检查模型时,它具有更改的值.但响应流具有旧值.

最终我发现了你做过的同样的工作:

public ViewResult SomeAction(SomeModel model) 
{
    var newModel = new SomeModel { SomeString = "some value" };
    ModelState.Clear();
    return View(newModel); 
}
Run Code Online (Sandbox Code Playgroud)

按预期工作.

我不认为这是一个"功能",是吗?

  • 这仍然是事实,包括我在内的很多人都因此而失去了很多时间.错误或设计,我不在乎,这是"意外". (36认同)
  • 刚做了几乎与你完全相同的事情.但是,发现这不是一个错误.这是设计:[一个Bug?EditorFor和DisplayFor不显示相同的值](http://forums.asp.net/p/1527149/3687407.aspx)和[ASP.NET MVC的Html Helpers渲染错误的值](http://blogs.msdn .COM/b/simonince /存档/ 2010/05/05/ASP净MVC-S-HTML的助手渲染最错value.aspx) (32认同)
  • 伙计,我已经花了2个小时与它斗争.感谢您发布此答案! (8认同)
  • 我刚刚花了四个小时.丑陋. (8认同)
  • 我同意@Proviste,我希望将来删除这个"功能" (7认同)
  • 由于这种令人讨厌的行为,我已经失去了至少两天的开发时间.让我们知道:如果您在javascript中序列化表单并将内容提交给控制器,以便控制器可以随后修改模型并返回结果,结果将不是您所期望的.确保在控制器的action方法中发现ModelState.Clear(). (5认同)
  • ASP.NET MVC 5.2中存在此问题 (3认同)
  • 该死的!花了很多时间来讨论ajhuddy面临的同一个问题 (2认同)

Mat*_*caj 42

更新:

  • 这不是一个错误.
  • 请停止View()从POST操作返回.如果操作成功,请改用PRG并重定向到GET.
  • 如果您返回View()从POST动作,连续做表单验证,并做到这一点的方式MVC设计使用内置的助手.如果你这样做,那么你不应该使用.Clear()
  • 如果您正在使用此操作返回SPA的 ajax ,请使用web api控制器并忘记,ModelState因为您无论如何都不应该使用它.

老答案:

MVC中的ModelState主要用于描述模型对象的状态,主要与该对象是否有效有关.本教程应该解释很多.

通常,您不需要清除ModelState,因为它由MVC引擎为您维护.在尝试遵守MVC验证最佳实践时,手动清除它可能会导致意外结果.

您似乎正在尝试为标题设置默认值.这应该在模型对象被实例化时(在某个地方或在对象本身 - 无参数的ctor中),在get动作上进行,以便它第一次或完全在客户端(通过ajax或其他)下载到页面这样看起来好像用户输入了它,然后它返回了已发布的表单集合.一些如何在接收表单集合时添加此值的方法(在POST操作//编辑中)导致这种奇怪的行为可能导致.Clear() 看起来适合您.相信我 - 你不想使用clear.尝试其他一个想法.

  • 我并没有真正购买这个参数来*停止*从[HttpPost]函数返回View(...).如果您通过ajax发布内容,然后使用生成的PartialView更新文档,则MVC ModelState已显示为不正确.我找到的唯一解决方法是在控制器方法中清除它. (4认同)

小智 17

如果要清除单个字段的值,那么我发现以下技术很有用.

ModelState.SetModelValue("Key", new ValueProviderResult(null, string.Empty, CultureInfo.InvariantCulture));
Run Code Online (Sandbox Code Playgroud)

注意:将 "Key"更改为要重置的字段的名称.


JOB*_*OBG 6

那么ModelState基本上在验证方面保持了模型的当前状态

ModelErrorCollection:表示模型尝试绑定值时的错误.恩.

TryUpdateModel();
UpdateModel();
Run Code Online (Sandbox Code Playgroud)

或者像ActionResult中的参数

public ActionResult Create(Person person)
Run Code Online (Sandbox Code Playgroud)

ValueProviderResult:保存有关尝试绑定到模型的详细信息.恩.AttemptedValue,Culture,RawValue.

必须谨慎使用Clear()方法,因为它可能导致意外结果.并且您将失去ModelState的一些不错的属性,如AttemptedValue,MVC在后台使用它来在出错时重新填充表单值.

ModelState["a"].Value.AttemptedValue
Run Code Online (Sandbox Code Playgroud)


小智 6

我有一个实例,我想更新一个总结形式的模型,并且不想因为性能原因而"重定向到行动".隐藏字段的先前值保留在我更新的模型上 - 导致各种问题!

几行代码很快就确定了我想删除的ModelState中的元素(在验证之后),因此在表单中使用了新值: -

while (ModelState.FirstOrDefault(ms => ms.Key.ToString().StartsWith("SearchResult")).Value != null)
{
    ModelState.Remove(ModelState.FirstOrDefault(ms => ms.Key.ToString().StartsWith("SearchResult")));
}
Run Code Online (Sandbox Code Playgroud)


Tob*_*s J 5

我们很多人似乎都被这个咬了,虽然这种情况发生的原因是有道理的,我需要一种方法来确保模型上的值显示出来,而不是ModelState.

有些人建议ModelState.Remove(string key),但是key应该是什么并不明显,特别是对于嵌套模型.以下是我提出的一些方法来帮助解决这个问题.

RemoveStateFor方法将获取ModelStateDictionary所需属性的a ,Model和表达式,并将其删除.HiddenForModel可以在View中使用,仅使用Model中的值创建隐藏的输入字段,方法是先删除其ModelState条目.(这可以很容易地扩展为其他帮助扩展方法).

/// <summary>
/// Returns a hidden input field for the specified property. The corresponding value will first be removed from
/// the ModelState to ensure that the current Model value is shown.
/// </summary>
public static MvcHtmlString HiddenForModel<TModel, TProperty>(this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TProperty>> expression)
{
    RemoveStateFor(helper.ViewData.ModelState, helper.ViewData.Model, expression);
    return helper.HiddenFor(expression);
}

/// <summary>
/// Removes the ModelState entry corresponding to the specified property on the model. Call this when changing
/// Model values on the server after a postback, to prevent ModelState entries from taking precedence.
/// </summary>
public static void RemoveStateFor<TModel, TProperty>(this ModelStateDictionary modelState, TModel model,
    Expression<Func<TModel, TProperty>> expression)
{
    var key = ExpressionHelper.GetExpressionText(expression);

    modelState.Remove(key);
}
Run Code Online (Sandbox Code Playgroud)

从这样的控制器调用:

ModelState.RemoveStateFor(model, m => m.MySubProperty.MySubValue);
Run Code Online (Sandbox Code Playgroud)

或者从这样的观点来看:

@Html.HiddenForModel(m => m.MySubProperty.MySubValue)
Run Code Online (Sandbox Code Playgroud)

它用于System.Web.Mvc.ExpressionHelper获取ModelState属性的名称.