Html. textbox extension in ASP. net mvc. Its behavior may not be what you expected

Source: Internet
Author: User

Using ASP. net mvc as a website, the most common extension is probably html. textbox extension, but in some specific circumstances, its behavior may not be what you expected. Let's take a look at this specific situation.

To illustrate the problem, we assume there is such a modal type:

/// <Summary> /// my object /// </Summary> public class myobject {// <summary> /// ID /// </Summary> public int ID {Get; set ;}//< summary> /// name /// </Summary> Public string name {Get; Set ;}}

Then you obtain an instance and a list of the object in the Controller action, and

ViewData["myObjects"] = myObjects;return View(myObject);

Output the instance and the list to the view. In the view, you want to edit each object in the list. Therefore, you may have written code similar to the following:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyObject>" %>

<Div class = "Clearfix"> <Div class = "namediv"> ID: </div> <Div class = "contentdiv"> <% = html. textbox ("ID", model. ID) %> </div> <Div class = "Clearfix"> <Div class = "namediv"> Name: </div> <Div class = "contentdiv"> <% = html. textarea ("ID", model. name) %> </div>
<Div class = "Clearfix"> <% foreach (VAR item in myobjects) {%> <Div class = "Clearfix"> <Div class = "namediv"> ID: </div> <Div class = "contentdiv"> <% = html. textbox ("ID", item. ID) %> </div> <Div class = "Clearfix"> <Div class = "namediv"> Name: </div> <Div class = "contentdiv"> <% = html. textbox ("name", item. name) %> </div> <% }%> </div>

If you are like me, HTML is used in this loop. textbox, HTML. hidden or any input type extension, and HTML. textarea extension. Congratulations, you will see the result you don't want to see.

What results will be seen? Except that the first myobject outputs its value, the remaining values are also changed to the value of the first object. That is, if the name of your first object is "myobject1", you can see "myobject1" in addition to the first "name" input box, all the remaining "names" are displayed in the input box "myobject1 ".

Why? Let's take a look at the source code of the HTML. textbox extension! (I am running the RC version code, but the problem is also true in the official version V1 ).

The source code is in the inputextensions file of the MVC/html folder of the system. Web. MVC project. First, let's look at the signature and implementation of the extension we used above:

public static string TextBox(this HtmlHelper htmlHelper, string name, object value) {           return TextBox(htmlHelper, name, value, (object)null /* htmlAttributes */);       }

Let's go with it.

return InputHelper(htmlHelper, InputType.Text, name, value, (value == null) /* useViewData */, false /* isChecked */,
true /* setId */, true /* isExplicitValue */, htmlAttributes);

Here. Let's take a look at the implementation of the inputhelper function:

Private Static string inputhelper (this htmlhelper, inputtype, string name, object value, bool useviewdata,
Bool ischecked, bool setid, bool isexplicitvalue, idictionary <string, Object> htmlattributes) {If (string. isnullorempty (name) {Throw new argumentexception (mvcresources. common_nullorempty, "name");} tagbuilder = new tagbuilder ("input"); // string valueparameter = convert, such as attribute name and type, is omitted. tostring (value, cultureinfo. currentculture); Switch (inputtype ){ // Case inputtype. checkbox: // case inputtype. Radio: // case inputtype. Password: Default: String attemptedvalue = (string) htmlhelper. getmodelstatevalue (name, typeof (string); tagbuilder. mergeattribute ("value ",
Attemptedvalue ?? (Useviewdata )? Htmlhelper. evalstring (name): valueparameter), isexplicitvalue); break;} If (setid) {tagbuilder. generateid (name);} return tagbuilder. tostring (tagrendermode. selfclosing );}

From the code above, I deleted a lot of code that is irrelevant to the textbox setting value. We don't care about the logic-controlled code, let's see how it sets the value for the labels whose input type is text or den:

string valueParameter = Convert.ToString(value, CultureInfo.CurrentCulture);

First, the above line of code converts any type of value we set to the string type. Next, let's look at the two rows in default:

string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter), isExplicitValue);

Now you see the most critical code. What is it doing? No matter whether the value parameter is set or not, it tries to take a value somewhere, and the obtained value has the highest priority. If it is not null, it is the value of the <input> tag. Where is the value?

Okay. Let's take a look at how htmlhelper. getmodelstatevalue (name, typeof (string) values are available?

internal object GetModelStateValue(string key, Type destinationType) {            ModelState modelState;            if (ViewData.ModelState.TryGetValue(key, out modelState)) {                return modelState.Value.ConvertTo(destinationType, null /* culture */);            }            return null;        }

We can see that it is taken from htmlhelper. viewdata. modelstate. Well, let's take a look at viewdata. modelstate. trygetvalue (Key, out modelstate ):

public bool TryGetValue(string key, out ModelState value) {           return _innerDictionary.TryGetValue(key, out value);       }

Now, we can see that it is based on the key value input from an internal dictionary. Where does the value of this internal Dictionary come from? That is, when was htmlhelper. viewdata. modelstate created and constructed its internal dictionary?

We know that each of our views has an HTML attribute, and we are still very comfortable with it. This stuff is htmlhelper. So how can each of our views have this attribute? Because each view is inherited directly or indirectly from the viewpage <tModel> or from the viewpage type. Then, let's see how viewpage <tModel> creates and initializes htmlhelper. Who is responsible for creating the view? We only return an instance of viewresult in a controller method. To clarify this problem, we need to talk about the entire MVC model once. Let's just look at a method of the controller class:

protected internal ViewResult View(object model) {            return View(null /* viewName */, null /* masterName */, model);        }

This is a common method called

protected internal virtual ViewResult View(string viewName, string masterName, object model) {           if (model != null) {               ViewData.Model = model;           }           return new ViewResult {               ViewName = viewName,               MasterName = masterName,               ViewData = ViewData,               TempData = TempData           };       }

We can see that the model we set is assigned to viewdata. model. Is this used to construct the internal Dictionary of htmlhelper. viewdata. modelstate we see above? I think so. At this point, you should understand why html. textbox is different from what we expected, because it always wants to take values from internal viewdata, while ignoring the values we explicitly set.

In this case, either write a textbox extension by yourself (not difficult, isn't it ?), Or use the <input> label, which is not very troublesome.

Note: This article does not discuss the application scenarios described in this article.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.