{"id":33,"date":"2010-04-17T14:04:01","date_gmt":"2010-04-17T14:04:01","guid":{"rendered":"http:\/\/blog.joefield.co.uk\/?p=33"},"modified":"2010-05-02T23:51:41","modified_gmt":"2010-05-02T23:51:41","slug":"digging-around-textboxfor-in-asp-net-mvc-2","status":"publish","type":"post","link":"https:\/\/blog.joefield.co.uk\/?p=33","title":{"rendered":"Digging around: TextBoxFor in ASP.NET MVC 2"},"content":{"rendered":"<p>This is a companion post to Scott Guthrie&#8217;s <a href=\"http:\/\/weblogs.asp.net\/scottgu\/archive\/2010\/01\/10\/asp-net-mvc-2-strongly-typed-html-helpers.aspx\" target=\"_blank\">ASP.NET MVC 2: Strongly Typed Html Helpers<\/a>.<\/p>\n<p>I was interested in what made this code:<\/p>\n<pre class=\"brush: xml;\">&lt;%= Html.TextBoxFor(model =&gt; model.ProductName) %&gt;<\/pre>\n<p>in an aspx view template produce this html:<\/p>\n<pre class=\"brush: xml;\">&lt;input id=&quot;ProductName&quot; name=&quot;ProductName&quot; type=&quot;text&quot; value=&quot;Aniseed Syrup&quot; \/&gt;<\/pre>\n<p>In order to do it ASP.NET MVC has performed two distinct operations:<\/p>\n<ol>\n<li>parsed the expression tree produced by the compiler for <strong>model =&gt; model.ProductName<\/strong> to extract the name of the property (&quot;ProductName&quot;) to use in the id and name attributes of the input element<\/li>\n<li>compiled the expression and invoked the resulting delegate to produce the &quot;Aniseed Syrup&quot; value<\/li>\n<\/ol>\n<h4>TextBoxFor extension method<\/h4>\n<p>The call to Html.TextBoxFor ends up in the following extension method in the InputExtensions class:<\/p>\n<pre class=\"brush: csharp; highlight: [8,9,10,11];\">public static MvcHtmlString TextBoxFor&lt;TModel, TProperty&gt;( \n    this HtmlHelper&lt;TModel&gt; htmlHelper, \n    Expression&lt;Func&lt;TModel, TProperty&gt;&gt; expression, \n    IDictionary&lt;string, object&gt; htmlAttributes) \n{ \n    return TextBoxHelper( \n        htmlHelper, \n        ModelMetadata.FromLambdaExpression(\n            expression, \n            htmlHelper.ViewData).Model, \n        ExpressionHelper.GetExpressionText(expression), \n        htmlAttributes); \n}<\/pre>\n<p>I&#8217;ve highlighted the second and third parameters. The call to TextBoxHelper() does the final rendering by:<\/p>\n<ul>\n<li>calling Convert.ToString() on the second parameter to populate the value attribute of the input element<\/li>\n<li>using the third parameter to populate the name and id attributes of the input element<\/li>\n<\/ul>\n<p>But let&#8217;s backtrack a bit first and look at the TextBoxFor signature itself.<\/p>\n<h4>Quick detour to Expression&lt;Func&lt;TModel, TProperty&gt;&gt;<\/h4>\n<p>Here&#8217;s the signature of the TextBoxFor method in the previous section:<\/p>\n<pre class=\"brush: csharp; highlight: [3];\">public static MvcHtmlString TextBoxFor&lt;TModel, TProperty&gt;( \n    this HtmlHelper&lt;TModel&gt; htmlHelper, \n    Expression&lt;Func&lt;TModel, TProperty&gt;&gt; expression, \n    IDictionary&lt;string, object&gt; htmlAttributes) \n{ \n... \n... \n} <\/pre>\n<p>By declaring a parameter of type <strong>Expression&lt;Func&lt;TModel, TProperty&gt;&gt;<\/strong> the TextBoxFor method has asked the compiler to generate an expression tree rather than a delegate. <\/p>\n<p><strong>Expression&lt;TDelegate&gt;<\/strong> is derived from LambdaExpression, which represents an expression tree which can be compiled into a delegate by calling its Compile() method.<\/p>\n<p>Interestingly, the implementation of Compile() in <strong>Expression&lt;TDelegate&gt;<\/strong> calls Compile() on its base and casts the resulting delegate to <strong>TDelegate<\/strong>, so its a pretty thin wrapper for LambdaExpression.<\/p>\n<p>All these uses of the term &quot;lambda expression&quot; can be mighty confusing. We call<\/p>\n<pre class=\"brush: csharp;\">model =&gt; model.ProductName<\/pre>\n<p>a lambda expression when we see it in code. The compiler however will treat it as an anonymous function or an expression tree, depending on the context<\/p>\n<p>If it&#8217;s being assigned to <strong>Func&lt;TModel, TProperty&gt;<\/strong> it is treated as an anonymous function.<\/p>\n<p>But if it&#8217;s being assigned to <strong>Expression&lt;Func&lt;TModel, TProperty&gt;&gt;<\/strong> then it is treated as an expression tree.<\/p>\n<p>Anyway, back to the TextBoxFor method.<\/p>\n<h4>ExpressionHelper.GetExpressionText<\/h4>\n<pre class=\"brush: csharp;highlight:[11]\">public static MvcHtmlString TextBoxFor&lt;TModel, TProperty&gt;( \n    this HtmlHelper&lt;TModel&gt; htmlHelper, \n    Expression&lt;Func&lt;TModel, TProperty&gt;&gt; expression, \n    IDictionary&lt;string, object&gt; htmlAttributes) \n{ \n    return TextBoxHelper( \n        htmlHelper, \n        ModelMetadata.FromLambdaExpression(\n            expression, \n            htmlHelper.ViewData).Model, \n        ExpressionHelper.GetExpressionText(expression), \n        htmlAttributes); \n} <\/pre>\n<p>We want to get the text with which to populate the id and name attributes of our text box.<\/p>\n<p>Because MVC has an expression tree rather than a delegate it can can pick it apart to find out, in this case, the name of the property being accessed.<\/p>\n<p>Here&#8217;s my stripped down version of the implementation of <strong>GetExpressionText()<\/strong>, which covers the case of our simple model.ProductName property access:<\/p>\n<pre class=\"brush: csharp;\">public static string GetExpressionText(LambdaExpression expression) \n{ \n    MemberExpression memberExpression = (MemberExpression)expression.Body; \n    return memberExpression.Member.Name; \n}<\/pre>\n<p>The body of the expression is cast to a MemberExpression so that its Member.Name property can be accessed.<\/p>\n<p>This returns &quot;ProductName&quot;.<\/p>\n<p>That was easy. Now on to the evaluation of the expression itself.<\/p>\n<h4>ModelMetadata.FromLambdaExpression<\/h4>\n<pre class=\"brush: csharp; highlight: [8,9,10];\">public static MvcHtmlString TextBoxFor&lt;TModel, TProperty&gt;( \n    this HtmlHelper&lt;TModel&gt; htmlHelper, \n    Expression&lt;Func&lt;TModel, TProperty&gt;&gt; expression, \n    IDictionary&lt;string, object&gt; htmlAttributes) \n{ \n    return TextBoxHelper( \n        htmlHelper, \n        ModelMetadata.FromLambdaExpression( \n            expression, \n            htmlHelper.ViewData).Model, \n        ExpressionHelper.GetExpressionText(expression), \n        htmlAttributes); \n} <\/pre>\n<p>OK so we&#8217;ve got hold of of the string <\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a companion post to Scott Guthrie&#8217;s ASP.NET MVC 2: Strongly Typed Html Helpers. I was interested in what made this code: &lt;%= Html.TextBoxFor(model =&gt; model.ProductName) %&gt; in an aspx view template produce this html: &lt;input id=&quot;ProductName&quot; name=&quot;ProductName&quot; type=&quot;text&quot; value=&quot;Aniseed Syrup&quot; \/&gt; In order to do it ASP.NET MVC has performed two distinct operations: [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/33"}],"collection":[{"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=33"}],"version-history":[{"count":65,"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/33\/revisions"}],"predecessor-version":[{"id":108,"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/33\/revisions\/108"}],"wp:attachment":[{"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=33"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=33"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.joefield.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=33"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}