John Kaster

Behind the Screen

Powerful but easy paging with ASP.NET MVC

with 12 comments

Since I started following the public beta in mid-2008, I’ve been eagerly awaiting the release of ASP.NET MVC. Now that ASP.NET MVC 1.0 is released, I’ve been diving into it more, and fiddling with some DataSnap tooling to quickly generate the strongly typed models MVC works likes best. The EDN team is working on upgrades (replacements, really) to existing web applications, and also some new web applications based on ASP.NET MVC.

If you’re not familiar with ASP.NET MVC, my top recommendation is to read Scott Guthrie’s free 185 page tutorial. (This tutorial is one of the best tutorials I’ve ever read on the process of writing any application. There are many gems in there that go beyond just ASP.NET MVC.)

I have some friends using Developer Express XPO to develop both a WinForms GUI and an MVC interface. One of the things they were trying to figure out was how to page an XPCollection, which supports IEnumerable, and is similar to a strongly typed dataset. Paging a collection is something we definitely need for our EDN MVC applications as well, so I decided to investigate this. I used code from the MVCContrib project to implement collection paging for XPCollection (and other IEnumerable collections) in a generic but highly customizable and reusable way.

MVCContrib includes a PaginationHelper class for converting an enumerable collection to an interface called IPagination.For further information, please read Jeremy Skinner’s discussion of his excellent work on GridModels and Html.Pager().

Here’s a pattern to use to quickly make your IEnumerable collection pageable.

First, implement support for a nullable int page number in your controller action:

using MvcContrib.Pagination;
public ActionResult Index(int? page)
{
  var pageNo = page?? 1; // default to page 1
  var Customers = GetCustomers(); // returns your Enumerable collection
  var CustPage = PaginationHelper.AsPagination<Customer>(Customers, pageNo);
  return View(“Index”, CustPage);
}

Then, use MvcContrib.UI.Pager’s html helper for generating the paging control:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IPagination<Customer>>" %>
<%@ Import Namespace="MvcContrib.UI.Pager" %>
…
(your standard MVC code for iterating the collection, now a subset)
…
<%= Html.Pager(Model) %>

PaginationHelper.AsPagination casts Customers to an IPagination interface. One important change I had to make to this ascx code was to replace System.Web.Mvc.ViewUserControl<IEnumerable<Customer>> with System.Web.Mvc.ViewUserControl<IPagination<Customer>>. Once you do that, the call to Html.Pager() will automatically generate the paging UI for you, which defaults to using a URL parameter called “page” for indicating which page to select out of the collection.

The total number of items in the collection, the range of selected items, going to the first, previous, next, and last page of the collection are all automatically supported by Html.Pager().

Update: it was so late last night, I forgot to mention this post about XPO and LINQ support.

Advertisements

Written by John Kaster

April 2, 2009 at 11:49 pm

Posted in Delphi, EDN

12 Responses

Subscribe to comments with RSS.

  1. It would be great if Rad Studio 2007 was updated to support ASP.NET MVC… any chance to see this happen?

    Andrew

    Andrea Raimondi

    April 3, 2009 at 2:47 am

  2. It’s really odd that that pagination helper works on IEnumerable instead of IQueryable. Pagination is certainly something you want to do on the database server, not in your controller.

    I’m using this type, which works with IQueryable as well as IEnumerable:

    http://www.squaredroot.com/post/2008/07/08/PagedList-Strikes-Back.aspx

    This way I can pass it an IQueryable expression from LINQ to Entities, and when the View is executed the paging will be done by the database server. You can’t do that with IEnumerable.

    For granted, I’m using jqGrid. I’ve built helpers which work with the IPagedList class to return data in the JSON format the grid expects. I will blog this at some point.

    Craig Stuntz

    April 3, 2009 at 3:29 am

  3. Andrea, you’d have to ask Nick Hodges about ASP.NET MVC plans, but I think the best bet for MVC from us would be Delphi Prism. However, I am definitely interested in making it VERY easy to consume DataSnap data and procedures with MVC — and I’m nearly done with the tooling for that. My team shares our development with R&D, and I’ll be sure to give them access to whatever we end up building for DataSnap support in MVC.

    John Kaster

    April 3, 2009 at 8:33 am

  4. Craig, agreed that pagination is best on the database server. This helper ends up calling LazyPagination, which seems a reasonable compromise since it caches the fetched results, IIUC. Thanks for your other ref, and I look forward to your blog on IPagedList. I’ve been enjoying your blog posts on MVC. (And I still owe you a phone call or two to discuss some ideas!)

    This specific implementation isn’t optimal, but it’s certainly a great start. Until I tried this, I thought XPO didn’t support Skip() and Take() but the MVCContrib code definitely was working with XPCollection — so now I need to delve into the code more.

    I was so pleased it worked I just had to blog about it. I really expected there to be missing methods 🙂

    John Kaster

    April 3, 2009 at 8:37 am

  5. If you need something sooner, I can e-mail source examples. I have to clean them up (references to stuff I can’t post) before I can post in public.

    Craig Stuntz

    April 3, 2009 at 9:03 am

  6. Thanks for the offer, Craig. I won’t be back on this for a couple days, so I can wait for now. Need to get back to strongly typing DataSnap collections.

    John Kaster

    April 3, 2009 at 10:42 am

  7. How do you implement the IPagination class? I mean, I couldn’t see where the class is…

    imperialx

    April 16, 2009 at 10:20 pm

  8. imperialx, the IPagination class is in the MVCContrib project at http://mvccontrib.codeplex.com/.

    John Kaster

    April 16, 2009 at 10:34 pm

  9. What is the code definition for GetCustomers()?

    jd

    August 18, 2009 at 10:11 am

  10. jd, GetCustomers() returns IEnumerable.

    John Kaster

    October 21, 2009 at 2:39 pm

  11. I wrote a free asp.net mvc paging component called MvcPager,it has more features and support Ajax paging using MicrosoftAjax or jQuery script library,you can view online demo and download it from http://en.webdiyer.com/mvcpager

    Webdiyer

    February 23, 2010 at 9:17 pm

  12. jqGrid is a perfect example of how NOT to use MVC appropriately. The model should know nothing of the view whatsoever, so injecting code into your model that dictates settings to an external plugin that is view-centric is bad bad bad practice. If you ever decide to change your view, you shouldn’t have to touch the model. jqGrid completely defies that logic. Better to find an unobtrusive solution that lets you configure paging in the model, response in the controller and keeps ALL of the jQuery in the view alone. Even the controller shouldn’t know about jQuery (or any JS plugin/library for that matter)… it should just render a partial or JSON or XML or whatever data it needs to get back to the client… then let your JS handle the display/interaction of it within the view.

    Jen

    April 22, 2010 at 9:56 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: