Fickle Bits

You're doing it wrong.

Leveraging Existing ASP.NET Features in ASP.NET MVC

The following is an excerpt from my upcoming book, ASP.NET MVC in Action

Many of us have invested heavily in ASP.NET. With ASP.NET MVC now available as an alternative to WebForms, is all that knowledge lost? Do we have to relearn this platform entirely from scratch? You’ll be relieved to know that many of ASP.NET’s platform features work the same way they always have. Some ASP.NET server controls even work. In this chapter we’ll cover what works in ASP.NET MVC and what does not. By the end of the chapter, you should feel comfortable leveraging your existing knowledge of ASP.NET to build robust web sites with ASP.NET MVC.

8.1 ASP.NET Server Controls

As you just discovered, some ASP.NET server controls work with ASP.NET MVC, but which ones? How can we tell if a control will work or not? To put it simply, any control that depends on ViewState or generates post-backs will not work. Some controls will render, but they require a <form runat=”server”> which you might not want to add. Adding a server-side form tag will put hidden fields on the page for ViewState and event validation. The form will also POST to the same action you’re on, which is usually unacceptable.

Note:

The code you’ll read in this section is purely exploratory. Most of it contains hacks and other workarounds that go against the intended design of an MVC web application. The intent of this section is to see how far we can bend the framework without breaking it. Your authors would not recommend using most of these methods in a production application unless absolutely necessary.

8.1.1 The TextBox

The first control we’ll examine is the <asp:TextBox />. It renders as an <input /> HTML element. It requires a <form runat=”server”> tag to function, and will be given a generated ID, again which is what we’re trying to avoid here! Since it is a form field, and the form is required to be runat=”server”, it is crippled in its function. Figure 8.1 shows it in action, while Listing 8.1 shows the resulting HTML.

figure8_1 
Figure 8.1 - The TextBox renders correctly

Listing 8.2 - The resulting HTML for the TextBox is less than desirable

figure8_2

We can see here that the rendered HTML contains a lot of things that we didn’t ask for. In addition, notice that the form tag has an action attribute that we didn’t specify. This will prevent the form from submitting to an action that we request. Since a textbox in ASP.NET MVC is as simple as <%= Html.TextBox(“name”) %>, the TextBox server control offers no functionality - only baggage - for your ASP.NET MVC views.

8.1.2 Other Common Controls

We can see from our simple text box example that most ASP.NET WebForms input controls have little to offer. However, some of the controls have very functional rendered output. An excellent example is the <asp:Menu /> control. It doesn’t require or generate any post-backs and it doesn’t require view state. It simply renders HTML and JavaScript to allow elements to expand and hide on mouse events. Leaving aside that the <asp:Menu /> renders a nasty pile of HTML tables to display properly, it’s purely a client rendered control, and it works just fine in ASP.NET MVC. Luckily we can fix the poor markup with ASP.NET Control Adapters, which also function in ASP.NET MVC. Figure 8.3 demonstrates the menu control.

figure8_3

Figure 8.3 - The menu control renders, unfortunately the links require post-backs. More surgery is needed to make it function.

figure8_4

Figure 8.4 - The horrific markup that is rendered by the Menu control. Stay tuned for a better way.

While the <asp:Menu /> control renders properly, the links in the menu are post-back links, and don’t work. We could conjure up some javascript to alter this behavior, however doing so would just add to the mess. Additionally, take a look at the rendered markup in Figure 8.4. Hard-coded styles, deeply nested tables, highly obtrusive javascript make this tiny menu render nothing short of a headache.

Note:

This type of markup is a constant reminder of why we want more control over our HTML! Later, in Chapter 14 (Recipes) we’ll see how we can do much better. For now, let’s continue on with our exploration of ASP.NET server controls.

Two controls that would be hard to live without would be the <asp:TreeView /> and the <asp:Calendar />. The TreeView works fairly well, however it generates post-backs that do nothing. The visual aspect works just fine, however. The calendar relies heavily on post-back for navigation, so unfortunately it does not function in ASP.NET MVC.

I’ve so far neglected the big-daddy of ASP.NET server controls. That’s right; I’m talking about the GridView. The GridView is an interesting case, because it has so many different forms. At its simplest, the GridView is just an HTML table. It’s great for displaying tabular data. If we don’t require any post-back, then it should work, right? In short it does work, however there are a view gotchas along the way.

8.1.3 The GridView

The first issue you face is there is no declarative way to bind the GridView to data coming from ViewData. For this we can poke into the code-behind class, which up until now has been mostly useless. In standard ASP.NET Form, you can add an OnLoad event handler and set the grid’s DataSource property to the data coming from ViewData. Listing 8.1 shows how you might accomplish this. Another method you could employ is to take the data binding code and put it directly in the view markup, inside <% %> code blocks. Listing 8.2 demonstrates this. Both of these methods send bad vibes up my spine, but the point is that it is possible.

Listing 8.1 - Binding a GridView from the code-behind

1
public partial class grid : ViewPage<Customer[]>{ protected override void OnLoad(System.EventArgs e) {base.OnLoad(e);grid1.DataSource = ViewData.Model;grid1.DataBind(); }}

Listing 8.2 - Binding a GridView from the view itself

1
<% grid1.DataSource = ViewData.Model; grid1.DataBind();%>

You also have the option of using the DataSource controls such as ObjectDataSource, SqlDataSource, and XmlDataSource. Of course, in doing this you’ve completely circumvented the MVC pattern and placed all of your data access directly in the view!

figure8_5

Figure 8.5 - The GridView ren ders properly

Figure 8.5 shows our newly bound GridView in action. Unfortunately, that’s all you get, because none of the advanced features of the GridView will work. No sorting, paging, editing, or selecting. Because of this, it is of limited utility, and will probably only aid you during prototyping and demos.

All is not lost, however. In ASP.NET MVC you can achieve the holy grail of an editable data grid, complete with sorting, paging, and editing. You just have to structure it in a different way. You’ll see an example of this in Chapter 14 (Recipes).

8.1.4 So Where Do I Get The Good Stuff?

The examples I’ve shown here might give you a sour taste in your mouth about ASP.NET MVC. Before you scoff at it and decide that you don’t want to live without your TreeView and Menu controls, consider this: many thousands of samples online show how you can achieve the same functionality with a little bit of Javascript and CSS. These are freely available solutions that many other platforms leverage. With ASP.NET MVC we can do the same, and with minimal friction in applying it. Often, these solutions are so simple; they make the declarative ASP.NET controls look like a sledgehammer. Here are a few references for platform-agnostic solutions to tree views, menus, and tabs using jQuery.

jQuery Treeview Examplehttp://jquery.bassistance.de/treeview/demo/

jQuery Menu Example

http://jdsharp.us/jQuery/plugins/jdMenu/
jQuery Tabs Example

http://stilbuero.de/jquery/tabs/

 

______________________________

For more early sections of ASP.NET MVC in Action, check out the pre-release PDFs available at Manning Press.

My co-authors may also be posting some excerpts, so pay attention to them:  Jeffrey Palermo and Jimmy Bogard.

Comments