MVC paged list

The need

As certain as the sun rising tomorrow, there will come the point where you will want to display a list or grid with paging. While many solutions exist, and many component developers are coming in with robust solutions, a simple and satisfactory solution can be created fairly easily.

Implementation

Why create a pager from scratch? Several reasons:

  1. You want to control the pager completely - display, style and all.
  2. You don’t like the idea of JavaScript paging, which will load your hundreds of pages to the browser and do client side paging / grid
  3. You want to understand and control exactly how a page subset of record is fetched and take control of database or IO thrashing

Of the quickly surveyed solutions out there, I found this one simple and straightforward. Being small, straightforward and simple means also easy to maintain, extend or modify. Based on that solution, I’ve created my own pager which breaks into 2 class implementations and one usage guidance.

The first class, is the PagedList class. The whole class is rather small and the only crux is doing correct math and ensuring the logic handles zero items returned. This class is responsible for taking a source list of all items (more on that below in the performance considerations) and presenting simple properties for HasNextPage, HasPreviousPage, TotalPages and CurrentPage. The implementation inherits from the generic List<T>, and so exposes and enumerator and the Count property. The constructor copies only the current page’s worth of items into the instance though, so Count will return the number of items on the current page (0 to page size) therefore an additional property TotalItems is populated upon construction which exposes the total number of items in the underlying source.

using System;
using System.Collections.Generic;
using System.Linq;
namespace BL.Models
{
/// <summary>
/// Adapted from http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/
/// </summary>
/// <typeparam name="T">The type of item this list holds</typeparam>
public class PagedList<T> : List<T>, IPagedList
{
/// <summary>
/// Initializes a new instance of the <see cref="PagedList&lt;T&gt;"/> class.
/// </summary>
/// <param name="source">The source list of elements containing all elements to be paged over.</param>
/// <param name="currentPage">The current page number (1 based).</param>
/// <param name="pageSize">Size of a page (number of items per page).</param>
public PagedList(IEnumerable<T> source, int currentPage, int itemsPerPage)
{
this.TotalItems = source.Count();
this.ItemsPerPage = itemsPerPage;
this.CurrentPage = Math.Min(Math.Max(1, currentPage), TotalPages);
this.AddRange(source.Skip((this.CurrentPage - 1) * itemsPerPage).Take(itemsPerPage).ToList());
}
public int CurrentPage {get ;private set;}
public int ItemsPerPage { get; private set; }
public bool HasPreviousPage { get { return (CurrentPage > 1); } }
public bool HasNextPage { get { return (CurrentPage * ItemsPerPage) < TotalItems; } }
public int TotalPages { get { return (int)Math.Ceiling((double)TotalItems / ItemsPerPage); } }
public int TotalItems { get; private set; }
}
}

PagedList implements the interface IPagedList, since a static class can not be generic, and the control renderer will need access to the PagedList’s properties:

using System;
namespace BL.Models
{
public interface IPagedList
{
int CurrentPage { get; }
bool HasNextPage { get; }
bool HasPreviousPage { get; }
int ItemsPerPage { get; }
int TotalItems { get; }
int TotalPages { get; }
}
}

The second class is more like a custom web control. Since this is MVC, we are driven to use a helper like implementation. My approach to developing HTML helpers for MVC is to create an extension method on the System.Web.MVC.ViewPage type. This allows the use of the well known and tested HtmlTextWriter to render the actual HTML rather than creating angled brackets in strings on the fly. I find this approach both more true to the form - rendering output to the output stream and not composing a string to be copied later - and safe: using compliant well tested constants and constructs rather than typing in HTML and hoping your syntax and understanding of the tag is correct.

using System.Web.Mvc;
using System.Web.UI;
public static partial class HtmlHelpers
{
/// <summary>
/// Shows a pager control - Creates a list of links that jump to each page
/// </summary>
/// <param name="page">The ViewPage instance this method executes on.</param>
/// <param name="pagedList">A PagedList instance containing the data for the paged control</param>
/// <param name="controllerName">Name of the controller.</param>
/// <param name="actionName">Name of the action on the controller.</param>
public static void ShowPagerControl(this ViewPage page, IPagedList pagedList, string controllerName, string actionName)
{
HtmlTextWriter writer = new HtmlTextWriter(page.Response.Output);
if (writer != null)
{
for (int pageNum = 1; pageNum <= pagedList.TotalPages; pageNum++)
{
if (pageNum != pagedList.CurrentPage)
{
writer.AddAttribute(HtmlTextWriterAttribute.Href, "/" + controllerName + "/" + actionName + "/" + pageNum);
writer.AddAttribute(HtmlTextWriterAttribute.Alt, "Page " + pageNum);
writer.RenderBeginTag(HtmlTextWriterTag.A);
}
writer.AddAttribute(HtmlTextWriterAttribute.Class,
pageNum == pagedList.CurrentPage ? "pageLinkCurrent" : "pageLink");
writer.RenderBeginTag(HtmlTextWriterTag.Span);
writer.Write(pageNum);
writer.RenderEndTag();
if (pageNum != pagedList.CurrentPage)
{
writer.RenderEndTag();
}
writer.Write(" ");
}
writer.Write("(");
writer.Write(pagedList.TotalItems);
writer.Write(" items in all)");
}
}
}

The implementation creates a list of page numbers, with a link on each except for the current page. The link will be of the format "/{controller name}/{action name}/{page number}".

I have added conditional style attribute to the link so that you can style the current page differently from the other pages easily. Since you have the code, you can extend the resultant HTML as you wish. You might want to have text indication of “no more pages” or some indication if the list is empty etc.

Finally, you would want to make use of this shiny new widget. The steps are as follows

1) In your controller, create an action which takes the page number as it’s sole parameter. The action would then create a new instance of the PagedList, passing it the “full list” and the current page number from the parameter.

public ActionResult Page(int id)
{
List<Product> products = CatalogService.ListOpenProducts();
PagedList<Product> data = new PagedList<Product>(products, id, PAGE_SIZE);
return View(data);
}

2) Change / create a view which takes the PagedList as it’s model.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<BL.Models.PagedList<Product>>" %>

3) Place a call to the extension method to display the pager anywhere in your view (multiple placement allowed - you can put one on top and one on the bottom etc). Recall that the method ShowPagerControl() extends ViewPage, so the keyword this should show your intellisence for the method. If you chose a more complex model (MVVM ViewModel containing more data than just the paged list) then you would use Model.{paged list property name}. The use of the view as a bag of random data conjured up by string names should IMHO be universally abandoned and eliminated.

<% this.ShowPagerControl(Model, "Bids", "Page"); %>

Considerations

Take != load all + scroll

The PagedList implementation takes an IEnumerable<T> as it’s source data. Internally, it uses Linq syntax which would seem to require all items be loaded, and then skip the first N pages and take the next {page size} worth of items. If your underlying list of items is a huge DB call, you will find that troubling. What you might consider then will be to use deferred loading. Extend the Linq IQueryable<T> or ObjectQuery<T> and let the ORM of your choice do the paging in the database. If your ORM is eager loader, you will need to implement custom partial record loading and paging at the data source level. If it can defer loading you will be in better shape.

Conversely, you might want to actually eager-load all records at the first shot. This will provide you with 2 benefits: cachability and coherency. Loading all items into memory incurs one DB call overhead and the IO required for all records. If you load each page at a time, you would incur {page count} * page clicks DB call overheads which might exceed the former if users scroll often back and forth. Once you load the whole list, you can cache it in memory and expire it based on data change events. If you have the base list in memory, access to it incurs no more IO regardless of pager clicks. Another phenomena caching gets around is coherency problems. If you page ad the DB level and an item is inserted or deleted, the end user experiences skips or stutter items. A skip is when a user clicks from page 1 to 2 an item which was to be on page 2 now is in the range of page 1 because an item on page 1 was deleted. Going to page 2 skips this item, and paging back should reveal it but would be surprising to the user (because she just came from page 1 and it wasn’t there before) creating the appearnace of a skipped / missed item. A stutter is the reverse situation: user clicks from page 1 to 2, and an item from page 1 appears again on page 2. This happens when an item was added and “pushed” the repeat item into page 2 because of it’s sorting order. This appears to the user as a malfunction and may infuriate some enough to call customer service (alas, advising customers to adjust their medication does not actually calm them down). A solution to coherence is to cache the result list for each user, expiring the cache actively when navigating away or running a different query.

Conclusion

The code above and variations of it are fairly easy to create. If your favorite web control vendor has not solved this for you, if you want to take full control of your paging of if you are just naturally curious - it’s a great way to add paging to your MVC application.

MVC + ASP.Net template control and user control

Seeing that I can use a DataBoundControl such as DataList, and binding it to a source control is achievable – what next?

Data bound controls contain various templates. The usual suspects are the item template and alternating template (for a repeating object, with possible varied style), the header and the footer templates (for enclosing HTML pre/post wrap or header / footer effects).

Under MVC, all events are out the window. So we’re not concerned at all with event hookup. We might want to provide the various “modes” of display (Edit, Create, Delete etc) which align well with CRUD command structure and may map to MVC quite naturally. But for starters, my project’s requirements simply required styling of the repeating item to be easily controlled.

So rather than inline HTML in the tag, I wanted to use a user control (ASCX). This allows my to style the item once and re-use it in pop-ups or other areas of the site, not just the data list view.

The question becomes then – how do I pass data “down” to the user control? The answer turned out to be to easy – you don’t have to do anything! That’s right, the containing DataList gets bound to data. The user control then can pluck fields from the “data row” (each item in the bound list of the parent) by using the syntax Eval("{some property}")

So the steps are:

  1. Create your user control (MiniItem.ascx)
  2. Register the user control in the hosting ASPX page
  3. Include the user control in the item template of your data bound control

The user control is an .ascx file, but change it to just inherit from System.Web.UI.UserControl. This is MVC so code behind is left behind..

<%@ Control Language="C#" Inherits="System.Web.UI.UserControl" %>
<fieldset>
<legend>Oh Goodie!</legend>
<p>
Product ID:
<%#Eval("ProductID") %>
</p>
<p>
Title:
<%#Eval("Title") %>
</p>
<img src='/Content/ProductImages/<%#Eval("ImagePath") %>' alt='Image Path' />
<p>
Description:
<%#Eval("Description") %>
</p>
</fieldset>

Your host ASPX file will need to register your control type in order to use it, so up at the top you place:

<%@ Register Src="MiniItem.ascx" TagName="MiniItem" TagPrefix="uc1" %>

Now you can use the user control simply by adding it to the ItemTemplate tag:

<asp:DataList runat="server" ID="dataList" RepeatColumns="4" RepeatDirection="Horizontal">
<ItemTemplate>
<uc1:MiniItem ID="MiniItem1" runat="server" />
</ItemTemplate>
</asp:DataList>

There you have it. You can use the good concepts of ASPX and the controls and visual components you are familiar with. While HTML helpers and fluent interface libraries are popping up, some find it more convenient and easy to use the “old” familiar ASPX controls. There are some good reasons to learn new things and try new framework or software paradigms. However, we can also leverage many of the successful declarative features of ASPX as a templating engine to achieve rapid development and modular UI.

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