ASP.NET MVC 2: Strongly Typed Html Helpers

[In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu]

This is the first in a series of blog posts I’m doing on the upcoming ASP.NET MVC 2 release.  This blog post covers the new strongly-typed HTML helpers added with ASP.NET MVC 2.

Existing HTML Helper Methods

ASP.NET MVC 1 shipped with a set of HTML helper methods that can be used within view templates to help with the generation of HTML UI.  For example, to output a textbox you could write code (within your .aspx view template) using the Html.TextBox() helper method below:

image

The first parameter to the helper method above supplies the name/id for the textbox, and the second parameter specifies the value it should have.  The helper method above would then render HTML like below back to a browser:

image

New Strongly-Typed HTML Helper Methods

One of the common feature asks people had for ASP.NET MVC 2 was for us to also support strongly-typed HTML helpers that use lambda expressions when referencing models/viewmodels passed to a view template.  This enables better compile-time checking of views (so that bugs can be found at build-time as opposed to runtime), and also enables better code intellisense support within view templates.

New strongly-typed HTML helper methods are now built-into ASP.NET MVC 2.  These methods use a "Html.HelperNameFor()” naming convention. For example: Html.TextBoxFor(), Html.CheckBoxFor(), Html.TextAreaFor(), etc.  They support using a lambda expression to specify both the name/id of the element, as well as the value to render for it.

For example, using ASP.NET MVC 2 we can now use the new Html.TextBoxFor() helper in addition to the Html.TextBox() helper above:

image

Notice above how we do not need to specify the “ProductName” string parameter anymore – lambda expressions are flexible enough that we can retrieve both the name of the property/field on our model object in addition to its value.

Because the HTML helpers are strongly-typed, we also get full intellisense support for them within Visual Studio when writing the lambda expression:

image

The HTML rendered is the same as the late-bound version of our HTML helper shown previously:

image

List of Strongly-Typed HTML Helper Methods built-into ASP.NET MVC 2

ASP.NET MVC 2 has built-in support for the following strongly-typed HTML helpers:

HTML Element Helpers:

  • Html.TextBoxFor()
  • Html.TextAreaFor()
  • Html.DropDownListFor()
  • Html.CheckboxFor()
  • Html.RadioButtonFor()
  • Html.ListBoxFor()
  • Html.PasswordFor()
  • Html.HiddenFor()
  • Html.LabelFor()

Other Helpers:

  • Html.EditorFor()
  • Html.DisplayFor()
  • Html.DisplayTextFor()
  • Html.ValidationMessageFor()

I’ll be covering the new Html.EditorFor() and Html.DisplayFor() helper methods in a later blog post in this series when I cover the improved auto-scaffold functionality in ASP.NET MVC 2.  We’ll also be using the Html.ValidationMessageFor() helper in my next blog post in this series which covers the improved validation support within ASP.NET MVC 2.

Strongly-Typed HTML Helpers within Scaffolding

VS 2008 and VS 2010 both by default now use the new strongly-typed HTML helpers when “scaffolding” new strongly-typed view tempates using the “Add View” command. 

For example, let’s assume we had a simple “ProductsController” class like below that has an “Edit” action method that renders an edit form for a “Product” model class:

image

We can right-click within the Edit action method using Visual Studio and choose the “Add View” context menu command to create a view template.  We’ll choose to create an “Edit” template that is scaffolded using a Product object:

image

With ASP.NET MVC 2, the view template that is created by default now uses the new strongly typed HTML helper methods to reference the Product model object:

image

Summary

The strongly-typed HTML helpers included with ASP.NET MVC 2 provide a nice way to get better type-safety within your view templates.  This enables better compile-time checking of your views (allowing you to find errors at build-time instead of at runtime), and also supports richer intellisense when editing your view templates within Visual Studio.

Hope this helps,

Scott

54 Comments

  • That looks so clean. So would I be able to assume it's a two way binding on both response request?

  • Thanks Scott for the explanation,makes even more simpler to understand the sweden videos of mvc2 ! :)

  • I look forward to the series. I especially am interested in the "Areas" part of your series.

    I tried to use them a while back (early preview), but there still seemed to be things to be ironed out.

    I had wanted to use an Area to slowly migration from ASP.NET WebForms project to ASP.NET MVC. I was trying to put all the MVC stuff (MasterPages, CSS, Styles, Views, Controllers, Models, etc...) in an Area while keeping the WebForms stuff in the main root project.

    It seemed like a good idea at the time, but I had strange issues. Possibly I was using an Area for the wrong thing.

  • @Ronald,

    >>>>>>>> That looks so clean. So would I be able to assume it's a two way binding on both response request?

    Glad you like it! The helpers can be used to help assist with two-way binding. In my next blog post I'll cover some of the new validation features of ASP.NET MVC 2 - which will help provide a better sense of how end to end input works.

    Hope this helps,

    Scott

  • @Elijah,

    >>>>>> I look forward to the series. I especially am interested in the "Areas" part of your series.

    Areas have come a pretty long way since the first few previews - with the new tooling support in VS for them they are really easy to add and start using.

    You could use them for the migration approach you described above. With ASP.NET 4 this could get even better since you can now use the URL routing engine for both web forms and MVC - which would allow you to easily switch implementations between URLs.

    Hope this helps,

    Scott

  • @Darin,

    Probably the biggest difference since the early betas is the addition of several new strongly-typed helpers. Earlier previews had fewer methods. The conceptual model is the same though.

    Hope this helps,

    Scott

  • Hi Scott,
    Might I suggest using a syntax highlighter instead of images to show us your source code? It's easier to copy-paste and play with without having to type too much for the sake of experimenting.

  • I wrote a free asp.net mvc paging component called MvcPager, the implementation was based on your PagedList idea. It support both asp.net mvc 1.0 and 2.0 rc. hope anyone can find it's useful! the online demo and download can be find at: http://en.webdiyer.com.thanks!

  • Fantastic stuff, I'm already using it.
    How can I pass html attributes to those new helpers?

  • Hi Scott,
    Thanks for your blog series. What is the performance impact While using Strongly Typed Html Helpers?

  • Hi Scott,

    Will using a refactor function to rename a property on the model class also update strongly typed views?

  • The Html.LabelFor() helper currently doesn't let you choose the label text, it just uses the property name so your label comes out as "EmailAddress" instead of "E-mail Address:" or "Your email address:"

    I know I can set the label text via DataAnnotation attributes on the Model class, but I consider the label text as a display/view concern and don't want it on my Models. Also, I can't add custom attributes to the element. Any chance these might be fixed for the next release?

  • Hi Scott,
    Thanks for blog. It very helpful, I learn ASP MVC using it. Have questions about refactoring view.

    What about automatic refactoring views?
    And what about refactoring LINQ model?

    For example, I rename filed in LINQ and want get automatic rename it in view.
    Or less, I rename something in code, and want get automatic rename it in view.

  • Very clean and productive. What we are still wondering is when M$ will provide a nice toolset of controls for MVC, like the one we have for ASP.NET or WPF. I had a look at MVC Contrib but it's still beta. JQuery is fine but requires too much effort.

  • Hi Scott - nice to see that this is finally making its way into an official release: are there any compatibility issues or performance changes between this and the HtmlHelpers contained within the MVC Futures Assembly?

  • Hi Scott: thanks for the blog and MVC 1, 2 framework. And thanks to your team for the PDC videos--particularly like Stephen Walther's talks. This is perhaps a naive question, but are you aware of major customers where, for example, there are say a couple hundred developers developing and provisioning MVC-based apps in either a government or private-sector organization. Reason I ask is that I come from a mainframe-based OLTP background where there was a very well-defined structure for presentation (green screen View:( ) transaction routing (Controller) and app components (Controller) with canonical message interfaces--consider the CICS environment as an example. In that model, programmers of even modest ability could be productive because the entire framework was a "given". Some smart guys had already developed the customized components for them. All they had to do was take care of the Procedure Division code in their apps. In your travels, do you see large customers trying to leverage MVC to build out a framework for web apps such that the programmer only needs to plug in the Model components and, for the most part, the remainder of the framework (authentication, authorization, transaction routing, common-look-and-feel presentation, etc) is there, already, in the framework? I am considering undertaking this approach in our large government organization, because we simply have too many stovepiped apps with no common structure and every programmer needs to have a PhD in web development in order to put out an app. In reality, our mainframe, CICS-like applications have a much better framework than what I see available in the middle-tier systems today. Any thoughts are welcome. all the best

  • @HeartAttack,

    >>>>>>> Might I suggest using a syntax highlighter instead of images to show us your source code? It's easier to copy-paste and play with without having to type too much for the sake of experimenting.

    I've looked at this in the past - but have found that a lot of blog readers seem to have issues with various approaches. I've been using the image model mostly because that seems to be the only consistent way I've found that works everywhere.

    Hope this helps,

    Scott

  • @Kay,

    >>>>>> How can I pass html attributes to those new helpers?

    You can specify attributes the same as with the late-bound helpers - by passing an anonymous object with name/value pairs:

    model.ProductName, new { SomeAttributeName="SomeValue" }) %>

    Hope this helps,

    Scott

  • @Jon,

    >>>>>>> Will using a refactor function to rename a property on the model class also update strongly typed views?

    VS 2010 won't automatically update this with the initial release - it is something that this feature would enable in the future though. I'm not sure if Resharper will support this - they are adding some cool refactoring support for ASP.NET MVC.

    Hope this helps,

    Scott

  • Just wish we could pass extra data to the templated handlers.

  • @Dominic,

    >>>>>>> The Html.LabelFor() helper currently doesn't let you choose the label text, it just uses the property name so your label comes out as "EmailAddress" instead of "E-mail Address:" or "Your email address:" I know I can set the label text via DataAnnotation attributes on the Model class, but I consider the label text as a display/view concern and don't want it on my Models. Also, I can't add custom attributes to the element. Any chance these might be fixed for the next release?

    I checked with the team, and their feedback was that if you don't want to use the DataAnnotations approach the best way to generate the label is probably just to explicitly type a element - since that will give you total control over what is output.

    Hope this helps,

    Scott

  • It's very useful

  • @Scott

    >>>>>>> I checked with the team, and their feedback was that if you don't want to use the DataAnnotations approach the best way to generate the label is probably just to explicitly type a element - since that will give you total control over what is output.

    If I just explicitly type a element, then how do I reliably render the for="" attribute for the label? Since the 'for' attribute is suppose to point to the ID of the textbox control it's paired with. I loose the benfits of strongly typed Html Helpers do I not?

    Yes I suppose I could type this:

    Your e-mail address:
    m.EmailAddress) %>

    ...but it would be nice if I type this...

    m.EmailAddress, "Your e-mail address") %>
    m.EmailAddress) %>

    ...where the 'EmailAddress' property is strongly typed with errors picked up at compile time.

  • Thanks Scott,

    Great to see these methods added...
    but what about strongly typed ActionLinks?

  • That's really cool.

  • @Shiju/Nick,

    >>>>>>> What is the performance impact While using Strongly Typed Html Helpers?

    We've been performance tuning them the last few months. I believe for a hello world app the lambda based versions are within about 10% of the string based ones. For real world apps (that do data access and more logic) this should be negligible.

    Hope this helps,

    Scott

  • @SergXIIIth,

    >>>>> What about richer refactorings

    We don't currently support those type of view based refactorings out of the box with VS 2010 - although the lambda based helpers would now support something like that.

    Hopefully we can add features like this to VS in the future though.

    Hope this helps,

    Scott

  • @benn,

    >>>>>>> Hi Scott - nice to see that this is finally making its way into an official release: are there any compatibility issues or performance changes between this and the HtmlHelpers contained within the MVC Futures Assembly?

    I don't know of any - although it is possible that we might have tweaked the APIs a little when we moved them from futures. You should still be able to use the old futures helpers if you want to - although I'd probably recommend moving to the built-in ones with MVC 2.

    Hope this helps,

    Scott

  • @ptimothy,

    We do see a lot of people build their own app-level framework around ASP.NET (both MVC and WebForms) so that their developers can then more easily add logic specific to their app scenario. That can be a good practice for larger projects.

    Hope this helps,

    Scott

  • @Keff,

    >>>>>>> I am curious, does this use the same parsing-the-expression-tree trick

    Yes - I believe it uses the same approach (with some caching to make it faster). The expression tree walk APIs are actually built-into .NET and so provide a consistent way to to this across scenarios.

    Hope this helps,

    Scott

  • @Dominic,

    >>>>>>> I sent a follow up mail to the team on this. I'm not sure if they'll be able to add it in V2 - but they are looking at it.

    Hope this helps,

    Scott

  • @Anthony,

    >>>>>>> but what about strongly typed ActionLinks?

    We aren't adding built-in runtime helpers for this - but David Ebbo has created a nice VS tooling add-on that creates strongly-typed helpers you can use: http://aspnet.codeplex.com/wikipage?title=T4MVC_History

    Hope this helps,

    Scott

  • Very useful Article.

    Thanks,
    Thani

  • Thanks for sharing your knowledge with us. Keep it up.

  • this is absolutely fantastic, always cringed at the thought of specifying the name/id as a string, it's just way too un-clean for me

  • Thanks for sharing your knowledge with us. Keep it up.

  • Hi Scott,
    This looks useful indeed. Does this approach support complex nested ViewModels? Imagine a VM that exposes 2 properties, one is a list of Id, Descriptions to be bound to a drop down list (States), the other is the complex type to be bound (Address). Do the helpers support something like the following?

    m.Address.AddressLine1) %>

    m.Address.State, m.States) %>

  • @Dominic,

    >>>>>>> The Html.LabelFor() helper currently doesn't let you choose the label text, it just uses the property name so your label comes out as "EmailAddress" instead of "E-mail Address:" or "Your email address:" I know I can set the label text via DataAnnotation attributes on the Model class, but I consider the label text as a display/view concern and don't want it on my Models. Also, I can't add custom attributes to the element. Any chance these might be fixed for the next release?

    What about putting your DataAnnotations on a ViewModel? I think seperating the DataAnnotations from your "true" model will have other advantages as well.

  • I'm hoping that these strongly typed helpers also support attributes such as Max Length, CSS Class, OnClick, etc. in a more straight-forward way than the untyped equivs in MVC 1.0

  • Very clean and productive. What we are still wondering is when M$ will provide a nice toolset of controls for MVC, like the one we have for ASP.NET or WPF. I had a look at MVC Contrib but it's still beta. JQuery is fine but requires too much effort.

  • Neat and clean... thanks

  • Regarding showing images for demos - perhaps provide a download link or a pop-up window option which allow the readers to copy and paste from there if they choose so. I've seen this implemented on numerous development websites/blogs.

    Keep up the great work Scott!

    -Kyle

  • Hi Scott,

    Am I correct in assuming that the Html.DropDownListFor extension method isn't present in the version that shipped with Visual Studio 2010 Beta 2?

  • Dear Scott,

    Since in my idea these strongly typed HTML helpers are, in a sense, a means of declaratively defining one-way bindings from Model to the View, I wonder if:

    1- There could be a way to pass an object instance of a type other than Model from Controller to the View which would have some View-state related properties, like IsLastNameEnabled - exactly the MVVM scenario -, which would itself sit on / wrap a Model object and then the View could bind to it.

    2- There was a fluent style to ONE-WAY BIND several properties of a single HTML element to the properties of the aforementioned ViewModel object, something like this:

    viewModel.Property1)
    .Property2(viewModel => viewModel.Property2) %>

    I understand that these HtmlHelpers are for pure HTML elements and not .net HTML controls - and hence have a limited set of attributes -, but I'm kind of guessing here!

    Thanks.

  • Thanks for sharing, really like your view. Waiting for some more great articles like this from you in the coming days.

  • thanks for this new blog, but at this speed that MVC is changing it will be hard to keep on codes update.

  • Can i know the difference between AjaxExtensions and LinkExtensions differences ?

  • Scott, these are great but I'm trying to use them in a ViewUserControl which inherits a Model and it isn't working. Can they be used in a ViewUserControl or just a ViewPage?

  • @Lloyd,

    >>>>>>> Scott, these are great but I'm trying to use them in a ViewUserControl which inherits a Model and it isn't working. Can they be used in a ViewUserControl or just a ViewPage?

    That should work fine (I just tried and didn't have any problems with it). Are you sure you typed it correctly? If you still have problems send me email and we can take a look.

    Thanks,

    Scott

  • Looks really clean and good. Looking forward to your future articles.

  • Hi Scott,

    Thanks for the article, this is a better approach.
    One of the big challenges we have is formatting the value to be rendered in html. Is there a way you can take and apply a format string in the HTML helpers? Or maybe a redirect (function, interface) that can be provided to handle conversion of the value to the string? We don't want to have to pass the value, would polute too much the code in the view.
    Thanks,
    Luc

  • It is possible to add multiple html atrributes if I use an anonymous object?

    Im succeeding with this:

    x.Created, new Dictionary() { {"size", "8"},{"readonly", "readonly"}})%>

    But this isn't anomynous, hence I have to reference System.Collections.Generic?

    Can it be done smarter?

  • Scott;
    Has there been a significant change in Custom HTML/Ajax helper development? It seems that the custum static methods return value of string has been changed to MvcHtmlString, of which does not inherit from (string) nor is able to cast to as such. This chage removed the string.Replace(string,string) method. What was the reason for this change? How does this impact custom helpers already developed?

  • Hey Scott and thanks for your great blog posts!

    I'm wondering if you have any plans in the team to add overloads to the new helper methods so they accept additional html attributes, like the old helper methods not ending with "For" did. Sometimes it's needed to set a custom css class for example, and it's a shame to have to do custom helpers when the old ones actually supported that.

    // Martin

Comments have been disabled for this content.