ASP.NET MVC Release Candidate 2: I declare myself to be declarative!

Today is a happy day: we released ASP.NET MVC Release Candidate 2. We're getting ever-so-close to the final (RTM/RTW) release of ASP.NET MVC - it won't be long! We think we fixed all the highest priority issues so that everyone out there can build ASP.NET MVC applications without worrying that we're going to make some sudden changes that will break you. Please see Phil's blog post announcing the release.

In this blog post I'll introduce you to a feature that's not even part of the main ASP.NET MVC download. It's part of the separate MVC Futures download, which includes prototypes of features that we're thinking of including in a future version of ASP.NET MVC.

Introduction to the MVC Controls

Before we dig into the details, let's create a simple ASP.NET MVC application that uses the MVC Controls.

1. Download the MVC Futures binary from CodePlex.

2. Create a new MVC Web Application Project (if asked, feel free to not create a unit test project). Please note that you must have Release Candidate 2 installed. Each release of ASP.NET MVC has a matching release of MVC Futures. Mixing releases is not supported and usually doesn't work.

01-NewProject

3. Add a reference to the MVC Futures binary. Right-click on the References node in Solution Explorer and choose "Add Reference". Select the "Browse" tab and navigate to the location to which you saved Microsoft.Web.Mvc.dll, select the file, and select OK.

02-AddReference

03-References

4. Edit the web.config in the root of the application to include tag mappings to the MVC Futures namespace. This tells the ASP.NET parser where to locate the controls when you type in an <mvc:SomeControl> tag. There should already be some tag mappings listed - the only new tag mapping is the third one with "mvc" as the tag prefix.

<pages>
  <controls>
    <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    <add tagPrefix="mvc" namespace="Microsoft.Web.Mvc.Controls" assembly="Microsoft.Web.Mvc"/>
  </controls>
  ...

5. Start using the controls!

Let's start out with a simple scenario of updating some of the Account and Membership features of the default template to use the MVC Controls.

1. Open up the ~/Views/Account/LogOn.aspx view page. The markup there should include this text box:

<%= Html.TextBox("username") %>

2. Change the text box markup to use the MVC TextBox control:

<mvc:TextBox runat="server" Name="username" />

(Please note that it sometimes takes Visual Studio a few moments to recognize new tag mappings. If Intellisense doesn't show up, please just give it a minute.)

3. Run the application and click "Log On" at the top-right of the page.

04-Login

4. If all is well, the page should continue to have the exact same behavior as before. For example, if you immediately click "Log On" without typing in a username or password you should see the red highlight on the text box indicating an error.

05-errors

The idea of the MVC Controls is that they are largely modeled after the HtmlHelpers, and thus try to preserve all their behavior. This includes naming conventions, the markup they render, and usage of model state.

Advanced MVC Controls

For a more advanced scenario involving the MVC Controls I'd like to introduce the MVC Repeater control. In many ways it is very similar to the ASP.NET Repeater control, but the main difference is of course that the MVC Repeater has specific knowledge of ViewData.

1. In the application you already created, open ~/Controllers/HomeController.cs (Sorry, I don't have a VB sample!) and add this new action method and two classes:

public ActionResult ProductList() {
    List<Distributor> distributors = new List<Distributor> {
        new Distributor { DistributorID = 501, Name = "Joe's Shop", Location = "Redmond, WA" },
        new Distributor { DistributorID = 502, Name = "Jill's Shop", Location = "Los Angeles, CA" },
        new Distributor { DistributorID = 503, Name = "Jeremy's Shop", Location = "Boston, MA" },
    };

    List<Product> products = new List<Product> {
        new Product {
            ProductID = 1001, 
            Name = "LEGO Technic Off Roader", 
            UnitPrice = 119.99m,
            Distributors = new List<Distributor> { distributors[0], distributors[1] } },
        new Product { 
            ProductID = 1002, 
            Name = "Ferrari F430", 
            UnitPrice = 189000m, 
            Distributors = new List<Distributor> { distributors[0], distributors[1], distributors[2] } },
        new Product { 
            ProductID = 1003, 
            Name = "Five bedroom house in Bellevue, WA",
            UnitPrice = 540000m, 
            Distributors = new List<Distributor> { } },
        new Product { 
            ProductID = 1004, 
            Name = "Dell 2007FP LCD monitor", 
            UnitPrice = 439m,
            Distributors = new List<Distributor> { distributors[2] } },
    };

    ViewData["products"] = products;

    return View();
}

public class Product {
    public int ProductID { get; set; }
    public string Name { get; set; }
    public decimal UnitPrice { get; set; }
    public IEnumerable<Distributor> Distributors { get; set; }
}

public class Distributor {
    public int DistributorID { get; set; }
    public string Name { get; set; }
    public string Location { get; set; }
}

2. Right-click anywhere in the action method and choose Add View with the default options and select "Add":

06-addview

3. In the newly created view add this ASPX markup to the second content placeholder (right below the <h2> tag):

<mvc:Repeater runat="server" Name="products">
    <ItemTemplate>
        <b><mvc:Label runat="server" Name="Name" /></b>
        (PID#<mvc:Label runat="server" Name="ProductID" />)
        $<mvc:Label runat="server" Name="UnitPrice" /><br />
        Distributors:<br />
        <mvc:Repeater runat="server" Name="distributors">
            <ItemTemplate>
                - <b><mvc:Label runat="server" Name="Name" /></b>
                (DID#<mvc:Label runat="server" Name="DistributorID" />),
                located in <mvc:Label runat="server" Name="Location" /><br />
            </ItemTemplate>
            <EmptyDataTemplate>
                - Sorry, there are no distributors for this item<br />
            </EmptyDataTemplate>
        </mvc:Repeater>
        <br />
    </ItemTemplate>
</mvc:Repeater>
Please note that when you paste in the code Visual Studio might add an "ID" attribute to every control tag. You can delete all those attributes if you don't want them - but it's fine to leave them.

4. Run the page and you will get this nested databound rendering:

07-rendering

Advantages of MVC Controls Over Code Nuggets

If you've used the default WebFormViewEngine in ASP.NET MVC, you've certainly used this syntax somewhere in your views:

<%= Html.TextBox("FirstName") %>

What you might not know is that this syntax is called a "code nugget." While there is nothing inherently wrong with using code nuggets, one advantage of using MVC Controls is that they can provide a rich design-time experience. Many developers, even those who are familiar with the intricacies of HTML and CSS, like to get an accurate preview of what their page will look like without running the application.

If you've used ASP.NET Web Forms and controls such as the SqlDataSource and the GridView, you've seen how rich a design-time experience can be. Those controls include design time rendering previews, advanced template editing, and even wizards that walk you through the steps of configuring the controls.

The MVC Controls in the MVC Futures download are just a start: they certainly don't have the fit and finish that is seen in the SqlDataSource design-time experience. Like many rumors about ASP.NET MVC itself have stated, the beginnings of the MVC Controls were in fact written on an airplane!

Compare the areas in the following screen shot of the text box we created earlier to see the difference. The MVC Control has a proper preview, whereas the HTML Helper doesn't render at all.

08-DesignView

Disadvantages of MVC Controls

One of the biggest disadvantages of the MVC Controls is that there is a rather immediate limit to how you can use them. For example, take this relatively simple scenario with the regular TextBox HtmlHelper:

<%= Html.TextBox("FirstName", Model.FirstName.ToUpper()) %>

There is no simple way to do this with the MVC Controls because there is no place to add your own code to pre-process the values.

Another disadvantage is that the MVC Controls work only with the WebFormViewEngine. There are several other view engines out there that people have been using with ASP.NET MVC. Some of the popular third party view engines out there are Spark view engine, NHaml, and the view engines included in the MVC Contrib project, which are Brail, NVelocity, and XSLT.

For ASP.NET MVC 1.0 we decided on the MVC team to focus our efforts on features that have the widest possible benefit. In this case it meant writing helpers that worked with as many different view engines as possible.

As a slight bit of humor (though it's in fact serious), please refer to Eric Lippert's blog post How many Microsoft employees does it take to change a lightbulb?

The Future of the MVC Controls

As I mentioned in the top of the post, the MVC Controls are just a prototype. They are not complete; they are not set in stone; and there is no guarantee that they will ever be part of the main ASP.NET MVC download.

I already have a long list of improvements to make to the MVC Controls. I plan to add many more controls as well as more advanced features to existing controls.

If you have any feedback, comments, or suggestions on the MVC Controls feel free to post them here. We take all feedback seriously!

Some questions to think about:

  1. Do you see yourself using the MVC Controls?
    • If so, why?
    • If not, why not?
  2. What MVC Controls would you see yourself using the most? (Even ones that don't exist yet.)

24 Comments

  • How does it mapping the data?
    ViewData["products"] = ControlName ?

  • If so it will also work for ViewData.Model?

  • 1. The mapping of the ViewData is typically done via the control's "Name" property. In the repeater sample I used ViewData["products"] in the Controller and then in the View.

    2. It should work just fine with ViewData.Model as well since the controls all call ViewData.Eval() to get their data. This ends up doing late-bound access via property descriptors, but I don't know any way around that.

    Thanks for taking a look!

  • I'm not against mvc controls at all as long as I can control the mark-up. The repeater seems the most useful to me.

    Would be great if I could control the naming of a repeater's element id's.

  • Why the 'runat=server' ?

  • I do like how it looks, I haven't tried them out yet.

    The flexibility and ease of creating customer html helpers has been really nice.

    Perhaps a simple tutorial on using mvc controls is in order :)

  • The controls make sence as it would allow html designers to learn faster and make use of them. However, I would be concerned with falling back into the Classic ASP.NET trap where click and drag and code generation rules. Thanks fro bringing it to our attention, I will definitively look into it.

  • YES! YES! YES!

    I personally would prefer using controls over helper methods. Controls allow you to have optional parameters whereas helper methods require a long parameter list or multiple overloads. Controls also allow you to have a hierarchy (i.e. the repeater control) and a much more expressive way of specifying control parameters and options.

    That said, I like having both options (controls and helper methods).

    Regarding:



    One option would be to add Format property to the control for simple formatting such as dates, time and money. You could extend it beyond the typical options allowed by String.Format() to account for upper/lower-casing strings and other string related formatting. One could argue that you should move the formatting out of the View and either do it in the Controller or in the Model. That is another option.

    I would hope that the MVC control model would allow us to extend existing controls and create our own controls?

    While I'm not a huge fan of the designer (it somehow never happens to look exactly like it ends up looking in a browser), I really appreciate the option of using controls over HTML helper methods. I hope to see this really take off.

  • @Denny -
    &gt;&gt;&gt;&gt;&gt; Would be great if I could control the naming of a repeater's element id's.
    The repeater doesn't have any actual IDs of its own. Thus, you can put any HTML tag in there and generate a dynamic ID using databinding expressions. For example, you can place this in the ItemTemplate:
    &lt;ItemTemplate&gt;
    &lt;span id="&lt;%# GenerateID() %&gt;"&gt;
    &nbsp; &nbsp;... more stuff
    &lt;/span&gt;
    &lt;/ItemTemplate&gt;
    Due to a small bug in the Repeater that I just noticed you unfortunately can't do this:
    &lt;span id="&lt;%# "MyRepeaterRow_" + Container.DisplayIndex %&gt;"&gt;
    Because someone forgot to increment the DisplayIndex for each row - it's always 0 :) (Oops!)
    I'll make sure this is fixed for the next release. In the meantime you can edit the source code manually by adding a statement "index++;" to the Repeater.cs file in the downloadable source code ZIP. Add the statement at the end of the foreach() statement on around line 60.
    Thanks,
    Eilon

  • @Steve -
    &gt;&gt;&gt;&gt;&gt; Why the 'runat=server' &nbsp;?
    The ASP.NET parser requires a runat="server" attribute for a tag to be processed by the parser. If it's not there then the parser treats it as literal text. Having said that, we've heard from several people that they would love to eliminate the runat="server" attribute and we'll look into it. However, since ASP.NET MVC builds on top of ASP.NET 3.5, we can't change the parser in MVC itself.
    Thanks,
    Eilon

  • @Joe -
    &gt;&gt;&gt;&gt;&gt; Do these new MVC controls encode by default?
    Yes, they do! Well, unless I forgot to encode in some place. In fact, the &lt;mvc:Label&gt; control has a property to control how it encodes. You can set its EncodeType property to: Html, HtmlAttribute, or None. The default is HTML encoding.
    The Label control has a bunch of other neat features, such as an optional format string and optional automatic truncation of the text.
    Thanks,
    Eilon

  • @Eric -
    &gt;&gt;&gt;&gt;&gt; One option would be to add Format property to the control for simple formatting such as dates, time and money.
    Yes, I totally agree! In fact, the &lt;mvc:TextBox&gt;, &lt;mvc:Label&gt;, and a few other of the MVC Controls have a Format property where you can apply standard format strings. One obvious limitation of those is that if you're trying to do something that a string format can't do, you're out of luck. I like the idea of formatting in the Controller as well, but I'm sure many out there might not like it :)
    Thanks,
    Eilon

  • I'm a bit uncertain about the MVC Controls, but I agree that ASP.NET MVC is in serious need for a design time experience.

    My only concern is that the team stick with their architecture philosophy and not overly complicate things. If MVC Controls become part of the framework, they should remain simple and rely on the idea of HTML Helpers and not convolute the framework with more server controls. I like the simplicity of HTML Helpers.

  • @Jeremy -
    &gt;&gt;&gt;&gt;&gt; Just to let you know NHaml isn't considered obsolete - it was just moved from mvccontrib into its own project (http://code.google.com/p/nhaml)
    Oops, sorry about that! I misinterpreted what was listed on the MvcContrib.org site. I corrected the blog post to have the correct text and link. Thanks for pointing this out!
    Thanks,
    Eilon

  • Eilon,

    I love the creativity of the solution but I think it's the wrong way to go because it hides the code and implementation and it reminds me of Web Forms too much.

    Love the new cleanliness of MVC and I do think this detracts from that.

    HTML and views can be a little messy but that's the very thing - it's HTML and by it's very nature it's a little messy and verbose... not sure we want to hiding that away.

    I do love the way this gives us back the UI in the view but surely VS2010 can be enhanced to do this automatically?

    What are your thoughts on that?

    Cheers,
    Mike

  • So tempted to say "the bad old days of web forms"! So funny that my first reaction is probably in line with people seeing the angle-percent stuff again in MVC.

    I don't think I'll use it - if only because of the aesthetic. Lame answer - but... I'm lame!

  • quick question: Why do I see viewstate in these controls? shouldn't you configure the classes so that they don't allow it?

  • @Luis -
    &gt;&gt;&gt;&gt;&gt; Why do I see viewstate in these controls?
    Where do you see ViewState? In Intellisense? Or do you see ViewState being rendered in the page?
    The controls are still ASP.NET controls, and they can technically access ViewState, but none of them should actually be using ViewState. Also, the ViewState can't get rendered to the view if there's no &lt;form runat="server"&gt; (since that's what renders the ViewState in a regular ASP.NET WebForm page).
    If you're seeing ViewState-related stuff in Intellisense then that's more difficult (but not impossible) to make disappear.
    Thanks,
    Eilon

  • Don't like it :(

    IMO, the current model is more flexible and simple to express markup.




    Vladan

  • SOS SOS SOS!!! PLEASE!

    Databinding and controls lead very quickly to the mess that is WebForms. A simple search regarding databinding and webforms returns an infinite number of questions, answers and hacks.

    It is plain to see that EVERYONE has hassles with the most basic webforms - let alone ones that actually do more than list an entire database table. I can't believe that a single technology requires THAT much online support.

    PLEASE stop spending time on HTML server-side generation tools that do all this binding. They're limiting at best and a noose at worst.

    Rather put your time into a MS version of extjs (or similar). A framework that generates HTML on the client-side and binds to various JSON data sources at display time is FAR more appropriate. Put the "V" in MVC where it should be - on the client. The majority of the time, you need to manipulate the rendered HTML client-side without postbacks. Doing this with binding server-side causes all manner of hassles.

    Please reduce the pollution of forums, blogs, news groups that is webform-related support. You'd do the environment a favour too by saving Google the hassle of indexing it.

    Although these controls LOOK enticing, they are merely a sugar coating on what will definitely turn out to be a bad design choice for some poor sod who thought they could get things out the door fast - conveniently forgetting that functionality would eventually become a requirement.

    thanks for the time! :)

  • I just got back from vacation and am thus coming to this discussion a bit late. I'm also not sure if these did or did not make it into the final MVC package (my first project for the week is to catch up on the RTM bits). On quick glance, it doesn't look like this made the cut.

    Personally, I prefer not to use Visual Studio or visual designers for writing code and, therefore, the designer support of controls (be they user, HTML helper or other varieties) is of little benefit to me. However, there are two things that I prefer about the declarative syntax. First, it visually integrates better with markup thus increasing code readability. Second, because it's parameterized, it makes reading and editing the code much easier - particularly for non-developers (e.g., designers).

    I need to research more into how the MVC view engines work. From what I've seen, most view engines reinvent the syntax anyway and so while declarative controls wouldn't work with, say, Spark, neither would the HTML helper methods (without rewriting them to Spark syntax). The point being: all view engines seem to limit a user into a particular syntax anyway, so while a consideration it seems like the decision to change view engines is going to invalidate a lot of existing markup regardless.

  • hi, just discovered this nice post.
    really nice feature, but it's difficult to unleash all the features of mvc helpers using declarative controls.
    i think that html helpers are best suited when the layout of page is defined by a programmer that knows how to use all the oppurtunity, but i think that if a web designer is working to an mvc page(like personalize an blog application), it's better a control, so i think that mvc controls must concentrate on the configuration of the standard properties like classis, and in the easy selection of the properties in the model and in the metadata

  • How to create custom control like textbox and save that textbox data into database in ASP.NET using MVC

  • Hi there this is kinda of off topic but I was wanting to
    know if blogs use WYSIWYG editors or if you have to manually
    code with HTML. I'm starting a blog soon but have no coding know-how so I wanted to get advice from someone with experience. Any help would be greatly appreciated!

Comments have been disabled for this content.