+N Consulting, Inc.

MVC, helpers and classic ASP.NET data bound controls – Better Together

In this article we’ll explore the use of classic ASP.NET controls in combination with extension methods in the MVC framework in order to facilitate development while remaining true to the MVC pattern and best practices.

A lot of hype around MVC these days. So, of course, yours truly is working on some project utilizing MVC. While brushing the dust off my raw HTML tag memory and designing the obvious: lists, grids, repeated item displays and the such, I thought “why not use the asp.net controls instead?”

For one, most of the ASP.NET data bound controls have a rich site of event post backs to hook up. MVC says: no dice! You can’t rely on the event dispatch loop of asp.net. In fact, this is the whole point of going MVC – to create a simple, well separated delineation between the presentation and the BL. If you have all these states and post back logic pieces all in the code behind you really have a tightly coupled application.

What is available though, is the rendering of most controls. So instead of “for each” and “if” statements sprinkled in the “presentation” template, you can actually just use the plain old asp.net controls declaratively. I put “presentation” in quotation marks because the more code (branching is code!) you have in the View, the more brittle it becomes, the more tightly coupled to BL it is and the less testable it is.

The main advantages I find in using the old controls is that:

  1. Familiarity – My developers know them already.
  2. Rich – Theming, localization behavior and layout aspects built in and available.
  3. Well tested – These controls have been around a while, and are generally well behaved.
  4. Modular – The controls isolate the presentation of a particular element and divorce it from the surrounding. In particular, it avoids issues of nesting and other inline logic in the presentation layer.

The main issue to overcome in a DataBoundControl is that with no code behind, how do you specify the data source declaratively? How do you do so with minimum code and maximum flexibility?

One solution is to use a data source object. Yes, they work. In most scenarios you can use them as you did before, but you must note that hooking up events (OnSelecting, OnSelected and the such) would again be challenging to do declaratively.

My approach for my project was to create an extension method for

DataBoundControl has a property “DataSource”, to which you assign an object that will be data bound. The most permissive base object System.Object, so we simply create an extension method:

using System.Web.UI.WebControls;

public static class DataboundControlExtensions
{
/// <summary>
/// Extends <typeparamref name="System.Object"/> to bind it to a <typeparamref name="System.Web.UI.WebControls.DataList"/>
/// </summary>
/// <param name="data">The data source object to bind.</param>
/// <param name="control">The control to bind the data source object to.</param>
public static void BindTo(this object data, DataList control)
{
control.DataSource = data;
control.DataBind();
}

/// <summary>
/// Extends <typeparamref name="System.Object"/> to bind it to a <typeparamref name="System.Web.UI.WebControls.ListView"/>
/// </summary>
/// <param name="data">The data source object to bind.</param>
/// <param name="control">The control to bind the data source object to.</param>
public static void BindTo(this object data, ListView control)
{
control.DataSource = data;
control.DataBind();
}
}

Note that the control is passed in as the target and is strongly typed. As it turns out, you get a runtime error if you attempt to specify the control parameter typed as DataBoundControl – the base class for all data bound controls. In other words, this doesn’t work:

public static void BindTo(this object data, DataBoundControl control) // Runtime error!

With the extension included in my project, I can now add the control and bind it in one code line:

<% Model.BindTo(dataList); %>
<asp:DataList runat="server" ID="dataList" RepeatColumns="2" RepeatDirection="Horizontal">
<ItemTemplate>
<fieldset>
<legend>
<%# Eval("ID")%></legend>
<p>
Title:
<%#Eval("Title") %>
</p>
<a href='<%#Eval("ImagePath") %>'>
<img src='<%#Eval("ThumbPath") %>' height="64" width="48" alt="pic"/></a>
<p>
Description:
<%#Eval("Description") %>
</p>
</fieldset>
</ItemTemplate>
</asp:DataList>

This is not as clean as completely declarative binding, but is much cleaner than having loop and branch constructs all over your view.

Most of you would note that the current MVC release includes HTML helpers. The Futures release is promising several more HTML helpers, which would provide with single line calls that would render lists, and other data bound presentation we are accustomed to. The reasons I didn’t use the futures HTML helper methods are:

  1. The futures were not in release yet at time
  2. I don’t love the mode in which the HTML helpers work
  3. The HTML helpers are not as rich as the asp.net components

The reason I don’t love the HTML helpers is simple: they are string valued functions. As string valued functions, they must, internally generate strings and throw away memory. Even when you use StringBuilder, the repetitive appendage of strings creates discarded buffers in the underlying byte array. Asp.Net controls, on the other hand, have access to the underlying output stream via a TextWriter. This means that the appended string snippets do not create intermediary buffers but rather get copied more efficiently to the actual byte stream that would be shipped to the browser.

So if I need to add an HTML helper to MVC what I do is write an extension method that extends System.Web.MVC.ViewPage, like so

using System.Web.Mvc;
using System.Web.UI;

public static class HelloKittyHelper
{
public static void Meow(this ViewPage page, string text)
{
HtmlTextWriter writer = new HtmlTextWriter(page.Response.Output);
if (writer != null)
{
writer.RenderBeginTag(HtmlTextWriterTag.Pre);
writer.Write(KITTY_ASCII);
writer.Write(text);
writer.RenderEndTag();
}
}
/// <summary>
/// ASCII art of a kitty - source unknown.
/// </summary>
private const string KITTY_ASCII = @"
.-. __ _ .-.
| ` / \ |
/ '.()--\
| '._/
_| O _ O |_
=\ '-' /=
'-._____.-'
/`/\___/\`\
/\/o o\/\
(_| |_)
|____,____|
(____|____)
";
}

Then pass it the data from the Model or anything you like from the view:

<%
this.Meow("purrr.. meow");
%>

With the ambient objects in the page, I just extend “this”, and internally utilize the HtmlTextWriter to write directly to the stream – no intermediary StringBuilder and hopefully less wasted immutable objects. The other advantage is that HtmlTextWriter can do things like begin/end tag tracking, add attributes and encode HTML as necessary. Leveraging existing well tested framework again, reducing costs of testing and education to deliver value early and often. In conclusion, we can use the new MVC concepts and remain true to the separation of view and logic by leveraging existing components and developing minimal custom extensions that help us avoid the pitfalls of “presentation logic”.

Localize your MVC with ease.

MVC seems all the rage these days. And while there are many good things it brings to the table, it seams it takes us a step back in terms of I18N.

For instance, if you want to use the special aspx attribute meta:resourceKey=”foo”, you won’t always be able to do so.

The following would work fine:

<asp:Label runat="server" ID="_QueryPrompt" Text="Enter Query" meta:resourcekey="_QueryPrompt" /> 

But we’re out of luck with buttons:

<asp:Button runat="server" ID="btn" Text="Run" meta:resourcekey="_SubmitQuery" />

At runtime, you will get an exception explaining you need a FORM with a runat=”Server”. Ugh. After some spelunking I came across this discussion, which basically suggests creating an extension to the System.Web.Mvc.HtmlHelper class. The discussion is thick with issues, specifically that if a UserControl is used, finding it’s path in order to get to it’s local resource requires all manners of digging around compilation and application with fairly extensive branching and parsing. Ultimately, the extension is complicated by attempting to combine both a resource retrieval, fallback to global from local resource and formatted template substitution in one. A good helper – if the kinks are worked out.

So I wrote my own syntactic sugar to do the same:

public static string Localize(this System.Web.UI.UserControl control, string resourceKey, params object[] args)
{
string resource = (HttpContext.GetLocalResourceObject(control.AppRelativeVirtualPath, resourceKey) ?? string.Empty).ToString();
return mergeTokens(resource, args);
}

public static string Localize(this System.Web.UI.Page page, string resourceKey, params object[] args)
{
string resource = (HttpContext.GetLocalResourceObject(page.AppRelativeVirtualPath, resourceKey) ?? string.Empty).ToString();
return mergeTokens(resource, args);
}

private static string mergeTokens(string resource, object[] args)
{
if (resource != null && args != null && args.Length > 0)
{
return string.Format(resource, args);
}
else
{
return resource;
}
}

It is substantially shorter and defers to a base class. System.Web.MVC.ViewUserControl inherits from System.Web.UI.UserControl, so the call is true to it’s application. I also extend System.Web.UI.Page.

Lastly, there is the issue of a global resource. Since these resources are compiled and accessed at design time using dot notation (MyGlobalRes.MyKey) I felt that providing an extra function would not significantly shorten code or simplify developer’s life. That is, given a resx file in the App_GlobalResources containing the file Zones.resx, containing a key Zone1 one would simply write out

<%= Resources.Zones.Zone1 %>

or – if your resource is a template requiring tokens to be merged:

<%= String.Format(Resources.Zones.Zone1,"foo",11) %>

Happy MVC Internationalization, localization and globalization!

Save The Date: time_t 1234567890

You know you are a geek when things like this seem of any importance.

It may comfort you to know that there are others who are excited about the buzz. It may disturb you. Make of it what you will:

On Friday, February 13th 23:31:30 UTC 2009 the time_t structure would contain the the number 1234567890

The time_t is measures seconds past midnight of January 1 1970 (see Unix Epoc, POSIX time etc)

You might celebrate UTC time - those of you not stuck in traffic in New York or at work in California. Or just do it according to your time zone: raise a toast, save some doughnuts from doughnut-Friday or look at the sky or do triple click an icon or something.

Here’s a little java script to sneak onto your website which shows the time and the countdown:

<script language="javascript" type="text/javascript"> 
function onTick()
{
var t = Math.floor( ((new Date()).getTime()) /1000);
var remaining = (1234567890 - t);
var display = "Now: " + t + ": " + remaining + " Sec. to 1234567890 (local time zone).";
document.getElementById("_ShowTime").innerHTML = display;
}
setInterval('onTick()', 1000);
</script>

Timing is everything

You know you have a problem when your app behaves badly.

You know you should do something about it when a customer complains

You know you are late when your competitor took away your customer.

Waiting for Pex to release

After seeing Pex in action at PDC 2008 I have caught the fever.

Since then, I gave it a whirle on my own and was pretty impressed. So much so, I chose it as a topic for one of my So-Cal Code Camp talks in January. Got some very good questions and concerns regarding the capabilities and place of Pex in the world of software development and vis-a-vis TDD.

** Update: After more than 5 years, Pex technology is now available as an “automatic unit testing” feature in some editions (paid) of Visual Studio 2015**

The Flash Myth

Frustrated with square looking web pages, many web designers look to Flash. In addition to freedom of graphic expression, Flash brings interaction and transition effects which are difficult or impossible to duplicate. Why then shouldn’t all websites be Flash laden? Several reasons pop to mind:

  1. Loading speed: Way too often, flash movies load complex graphics, forcing the viewer to stare at some progress bar. For people who want to quickly access information this is a huge turn off. A “skip intro” sometimes viewed as lame.

  2. SEO: Flash based sites rarely are digestible or well ranked by search engines. You use flash - you lose top slots in natural search results. It’s that simple

  3. Form over content: Flash designs - as beautiful and engaging as they may be - all too often sacrifice text and information quantity in order to not disturb the layout or fit within the containing graphics. Again, ranking will suffer (low authority), viewers seeking comprehensive data will navigate away or become frustrated attempting to dig up more details by clicking every button and link in the movie.

  4. Cost: Although many good web designers can produce Flash movies, the good ones are fewer and more expensive. The problem compounds with natural workplace attrition. The ability to modify the original design, extend the site or give the site a “facelift” becomes constrained or expensive. All too often the original design does not lend itself well to rearrangement or extension.

  5. QA: Automated testing of Flash UI sites is difficult or impossible because the results may not be capture-able by testing tools - and that’s in the good case where the inputs are automatable. Unit testing for ActionScript is available by supporting frameworks these days, but finding implementations which include continuous integration is still rare.

  6. Ease of use: Often, the design focus reflects the author’s perspective. As long as the viewer wants to view information the way the designer does, everything flows well. Once the viewer wants to navigate in a different way, all bets are off.

  7. Stickiness: By far, one of the more compelling reasons for having used a Flash based site was to engage the viewer and strengthen the brand. The delivery on the promise is a bit mixed. Although some interaction does increase the stickiness of the site, other designs may suffer from slow load and skimpy content actually detracting from the overall perceived quality.

If while reading the points mentioned above you think to yourself “It seems that many of the points indicate poor design - not a technology limitation” you are right, and I couldn’t agree with you more.

Yet a good amount of sites out there suffer from these issues. Most of these sites would have been better served producing an HTML / DHTML / CSS + Ajax etc. In fact, my motivation for writing this came from a restaurant website I visited today. While scanning through listings and attempting to learn more, I was forced to watch tab after tab of progress bar latency in order to see the menu, the location, the about us etc. That site would have been cheaper to upgrade by anybody, rank higher on search engines, load faster and create less frustrated visitors. The KISS principle does apply. The pictures were beautiful; the layout was very appealing, the information organized - but the experience utterly annoying. Is that the best impression the business owner could impart on a potential customers?

In another instance, I was searching for a specialty product, and found it about 40 miles away. After having spent the time driving there and making a purchase, I discovered a location much closer to my house. What made the different? The far store had a website with full online catalog in HTML. The close by store had a flash only site. Snazzy - but missed a sale.

I have been to some sites that make great use of Flash though, and it would be foolish to discount the technology for its potential pitfalls. On the contrary - its adoption and application should be studied and considered when new design projects com up. There are many sites containing laundry lists of good vs. bad design. This article is no such list. But when is Flash well suited?

  1. Where a custom tool is created for order processing. Photo order sites, custom printing, fashion model virtualization etc. In these cases Flash serves an interactive function and is typically not the whole site.

  2. Where little textual information is required. Walkthroughs, product 360 views, design concept sites targeting highly interested viewers who don’t mind waiting for content and where alternative information sources are not available.

  3. For isolated rich interaction: Games, presentations and doodads that keep the visitor happy watching and engaged - as a single section of the site.

  4. Offline (DVD, CD) or downloadable media presentations, manuals etc.

  5. Anywhere that you can do a better job at winning the mind of the visitor without losing another 3 along the way.

Bottom line - use it wisely. If you suspect that any of the problems mentioned above might harm your online business, consider alternatives. And yes, by all means - do use a flash player to play video clips on the net. It is very well suited for that.

Code Camp coming up

It’s that time of year again - Code Camp is next week, hosted at Cal State Fullerton.

Many good presenters, many good sessions.

Show up for one day both two, it’s free to attend!

Check it out, come by

Notice

We use cookies to personalise content, to allow you to contact us, to provide social media features and to analyse our site usage. Information about your use of our site may be combined by our analytics partners with other information that you’ve provided to them or that they’ve collected from your use of their services. You consent to our cookies if you continue to use our website.