asp.net-mvc ASP.Net MVC Html.HiddenFor 值错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4710447/
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-09-08 00:44:44  来源:igfitidea点击:

ASP.Net MVC Html.HiddenFor with wrong value

asp.net-mvcasp.net-mvc-3hidden-fieldshtml.hiddenfor

提问by willvv

I'm using MVC 3 in my project, and I'm seeing a very strange behavior.

我在我的项目中使用 MVC 3,我看到了一个非常奇怪的行为。

I'm trying to create a hidden field for a particular value on my Model, the problem is that for some reason the value set on the field does not correspond to the value in the Model.

我正在尝试为我的模型上的特定值创建一个隐藏字段,问题是由于某种原因,该字段上设置的值与模型中的值不对应。

e.g.

例如

I have this code, just as a test:

我有这个代码,只是作为一个测试:

<%:Html.Hidden("Step2", Model.Step) %>
<%:Html.HiddenFor(m => m.Step) %>

I would think that both hidden fields would have the same value. What I do is, set the value to 1 the first time I display the View, and then after the submission I increase the value of the Model field by 1.

我认为两个隐藏字段都具有相同的值。我所做的是,在第一次显示视图时将值设置为 1,然后在提交后将模型字段的值增加 1。

So, the first time I render the page both controls have the value 1, but the second time the values rendered are these:

所以,我第一次渲染页面时,两个控件的值都是 1,但第二次渲染的值是这些:

<input id="Step2" name="Step2" type="hidden" value="2" />
<input id="Step" name="Step" type="hidden" value="1" />

As you can see, the first value is correct, but the second value seems to be the same as the first time I display the View.

如您所见,第一个值是正确的,但第二个值似乎与我第一次显示视图时相同。

What am I missing? Are the *For Html helpers caching the values in some way? If so, how can I disable this caching?.

我错过了什么?*For Html 助手是否以某种方式缓存值?如果是这样,我如何禁用此缓存?

Thanks for your help.

谢谢你的帮助。

回答by Darin Dimitrov

That's normal and it is how HTML helpers work. They first use the value of the POST request and after that the value in the model. This means that even if you modify the value of the model in your controller action if there is the same variable in the POST request your modification will be ignored and the POSTed value will be used.

这是正常的,这就是 HTML 助手的工作方式。他们首先使用 POST 请求的值,然后使用模型中的值。这意味着即使您在控制器操作中修改模型的值,如果 POST 请求中存在相同的变量,您的修改也将被忽略并使用 POSTed 值。

One possible workaround is to remove this value from the model state in the controller action which is trying to modify the value:

一种可能的解决方法是从试图修改该值的控制器操作中的模型状态中删除该值:

// remove the Step variable from the model state 
// if you want the changes in the model to be
// taken into account
ModelState.Remove("Step");
model.Step = 2;

Another possibility is to write a custom HTML helper which will always use the value of the model and ignore POST values.

另一种可能性是编写一个自定义的 HTML 帮助程序,它将始终使用模型的值并忽略 POST 值。

And yet another possibility:

还有一种可能:

<input type="hidden" name="Step" value="<%: Model.Step %>" />

回答by Peter B

I encountered the same problem when writing a Wizard that shows different parts of a larger model at every step.
Data and/or Errors from "Step 1" would become mixed up with "Step 2", etc, until I finally realized that ModelState was to 'blame'.

我在编写一个向导时遇到了同样的问题,该向导在每一步都显示了较大模型的不同部分。
来自“第 1 步”的数据和/或错误会与“第 2 步”等混淆,直到我最终意识到 ModelState 是“责备”。

This was my simple solution:

这是我的简单解决方案:

if (oldPageIndex != newPageIndex)
{
    ModelState.Clear(); // <-- solution
}

return View(model[newPageIndex]);

回答by Ruslan Georgievskiy

This code will not work

此代码将不起作用

// remove the Step variable from the model state
// if you want the changes in the model to be
// taken into account
ModelState.Remove("Step");
model.Step = 2;

...because HiddenFor always (!) reads from ModelState not the model itself. And if it doesn't find the "Step" key it will produce the default for that variable type which will be 0 in this case

...因为 HiddenFor 总是 (!) 从 ModelState 读取而不是模型本身。如果它没有找到“Step”键,它将为该变量类型生成默认值,在这种情况下为 0

Here is the solution. I wrote it for myself but don't mind sharing it cause I see many people are struggling with this naughty HiddenFor helper.

这是解决方案。我是为自己写的,但不介意分享它,因为我看到很多人都在为这个顽皮的 HiddenFor 助手而苦苦挣扎。

public static class CustomExtensions
{
    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        string text = ExpressionHelper.GetExpressionText(expression);
        string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
        ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState;
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        if (modelState.ContainsKey(fullName))
        {                
            ValueProviderResult currentValue = modelState[fullName].Value;
            modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture);
        }
        else
        {
            modelState[fullName] = new ModelState
            {
                Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), CultureInfo.CurrentUICulture)
            };
        }
    }
}

Then you just use it as usual from within you view:

然后,您只需从视图中照常使用它:

@Html.HiddenFor2(m => m.Id)

It worth to mention it works with collections too.

值得一提的是,它也适用于集合。

回答by abdulkadir pekeroglu

I am too struggling with the same situation I think, where I use the same model state between calls, and when I alter a model property on backend. Though, it does not matter for me, if I use textboxfor or hiddenfor.

我在我认为的相同情况下太挣扎了,我在调用之间使用相同的模型状态,以及当我在后端更改模型属性时。不过,如果我使用 textboxfor 或 hiddenfor,这对我来说并不重要。

I just bypass the situation by using page scripts to store the model value as a js variable, because I need the hiddenfield for that purpose in the beginning.

我只是通过使用页面脚本将模型值存储为 js 变量来绕过这种情况,因为一开始我需要隐藏字段。

Not sure if this helps but just consider..

不确定这是否有帮助,但请考虑一下..