Possible bug in ASP.NET MVC with form values being replaced

后端 未结 12 627
抹茶落季
抹茶落季 2020-11-29 00:41

I appear to be having a problem with ASP.NET MVC in that, if I have more than one form on a page which uses the same name in each one, but as different types (radio/hidden/e

相关标签:
12条回答
  • 2020-11-29 00:45

    So in MVC 4 the "design problem" still there. Here's the code I had to use in order to set the correct hidden values in a collection since regardless of what I do in the controller, the view always showed incorrect values.

    OLD code

    for (int i = 0; i < Model.MyCollection.Count; i++)
    {
        @Html.HiddenFor(m => Model.MyCollection[i].Name) //It doesn't work. Ignores what I changed in the controller
    }
    

    UPDATED code

    for (int i = 0; i < Model.MyCollection.Count; i++)
    {
        <input type="hidden" name="MyCollection[@(i)].Name" value="@Html.AttributeEncode(Model.MyCollection[i].Name)" /> // Takes the recent value changed in the controller!
    }
    

    Did they fixed this in MVC 5?

    0 讨论(0)
  • 2020-11-29 00:47
    foreach (var s in ModelState.Keys.ToList())
                    if (s.StartsWith("detalleProductos"))
                        ModelState.Remove(s);
    
    ModelState.Remove("TimeStamp");
    ModelState.Remove("OtherOfendingHiddenFieldNamePostedToSamePage1");
    ModelState.Remove("OtherOfendingHiddenFieldNamePostedToSamePage2");
    
    return View(model);
    
    0 讨论(0)
  • 2020-11-29 00:47

    There is workaround:

        public static class HtmlExtensions
        {
            private static readonly String hiddenFomat = @"<input id=""{0}"" type=""hidden"" value=""{1}"" name=""{2}"">";
            public static MvcHtmlString HiddenEx<T>(this HtmlHelper htmlHelper, string name, T[] values)
            {
                var builder = new StringBuilder(values.Length * 100);
                for (Int32 i = 0; i < values.Length; 
                    builder.AppendFormat(hiddenFomat,
                                            htmlHelper.Id(name), 
                                            values[i++].ToString(), 
                                            htmlHelper.Name(name)));
                return MvcHtmlString.Create(builder.ToString());
            }
        }
    
    0 讨论(0)
  • 2020-11-29 00:47

    As others have suggested, I went with using direct html code instead of using the HtmlHelpers (TextBoxFor, CheckBoxFor, HiddenFor etc.).

    The problem though with this approach is that you need to put the name and id attributes as strings. I wanted to keep my model properties strongly-typed so I used the NameFor and IdFor HtmlHelpers.

    <input type="hidden" name="@Html.NameFor(m => m.Name)" id="@Html.IdFor(m=>m.Name)" value="@Html.AttributeEncode(Model.Name)">
    

    Update: Here's a handy HtmlHelper extension

        public static MvcHtmlString MyHiddenFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, object htmlAttributes = null)
        {
            return new MvcHtmlString(
                string.Format(
                    @"<input id=""{0}"" type=""hidden"" value=""{1}"" name=""{2}"">",
                    helper.IdFor(expression),
                    helper.NameFor(expression),
                    GetValueFor(helper, expression)
                ));
        }
    
        /// <summary>
        /// Retrieves value from expression
        /// </summary>
        private static string GetValueFor<TModel, TValue>(HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
        {
            object obj = expression.Compile().Invoke(helper.ViewData.Model);
            string val = string.Empty;
            if (obj != null)
                val = obj.ToString();
            return val;
        }
    

    You can then use it like

    @Html.MyHiddenFor(m => m.Name)
    
    0 讨论(0)
  • 2020-11-29 00:53

    Yes, this behavior is currently by design. Even though you're explicitly setting values, if you post back to the same URL, we look in model state and use the value there. In general, this allows us to display the value you submitted on postback, rather than the original value.

    There are two possible solutions:

    Solution 1

    Use unique names for each of the fields. Note that by default we use the name you specify as the id of the HTML element. It's invalid HTML to have multiple elements have the same id. So using unique names is good practice.

    Solution 2

    Do not use the Hidden helper. It seems like you really don't need it. Instead, you could do this:

    <input type="hidden" name="the-name" 
      value="<%= Html.AttributeEncode(Model.Value) %>" />
    

    Of course, as I think about this more, changing the value based on a postback makes sense for Textboxes, but makes less sense for hidden inputs. We can't change this for v1.0, but I'll consider it for v2. But we need to think through carefully the implications of such a change.

    0 讨论(0)
  • 2020-11-29 00:53

    Heads-up - this bug still exists in MVC 3. I'm using the Razor markup syntax (like that really matters), but I encountered the same bug with a foreach loop that produced the same value for an object property every single time.

    0 讨论(0)
提交回复
热议问题