In what now seems like ages ago, I once wrote about a paging solution that I had created for my ASP.NET MVC 1.0 applications in my article, "Add Paging Functionality to your ASP.NET MVC site." Over the years, I've used that solution in a few of my own ASP.NET MVC 1.0 and 2.0 applications and received several different requests for the code samples accompanying the article. However, I've always felt that paging solutions were a bit of a kludge that needed some serious help, additions, changes, and a thorough overhaul.
Building the Perfect ASP.NET Paging Solution
Recently, I found myself needing paging functionality in an app I was writing. Amazingly, it's actually also been a while since I've written an MVC app that really needed paging, so I haven't touched my paging functionality in quite a while. When I dusted it off recently, I felt the abject horror that most of us do when we look at code we've written years ago. Calling my previous solution sophomoric would have been generous. The code was filled with hideous coupling errors, it violated a couple of key tenets of MVC, and really left a lot to be desired. In its defense, though, it did actually get the job done early on—with a bit of a price.
Still, going forward, I wanted to build the perfect paging solution; something that took advantage of all the later MVC goodies, such as fun templates, expressions, and other improvements that shipped around the MVC 3.0 timeframe. To that end, I wanted very clean semantics, where objects were completely decoupled from rendering and presentation (i.e., HTML), and where I could easily unit test all of my assumptions and functionality to verify that things would behave as expected. Having a paging solution like that would let me avoid spending gobs of time debugging and troubleshooting HTML, outputs, and intermingled classes, as I've done in the past.
I created a quick laundry list of all the features this paging solution would need, only to realize that this wasn't going to be a simple undertaking. At that exact moment, I wondered if wasn't being a bit dumb to assume that nothing else was available. Happily, a bit of time on Google led me to a fantastic solution—one that exceeded my own needs and expectations.
Troy Goode's PagedList.MVC—A Fantastic Solution
Within just a few minutes of glancing at the samples on the PagedList.MVC GitHub page, I knew I had found a winner. The examples showed how the core functionality of this paging solution is effectively an extension of the same notion of an IPagedList<> that I had used in my own original solution, only the example was implemented in a much cleaner way and with better features and functionality than what I had initially created. In short, this was and is the solution I was dreaming of.
Deploying and using this paging solution was also trivial. Here's what I had to do, in case anyone else finds this article and is looking for simple instructions on how to add paging functionality to their ASP.NET MVC site:
- Install the PagedList.MVC package via Nuget. Right-click the References folder in your MVC project in Visual Studio 2012 or later version and select "Manage NuGet Packages." Wait for the NuGet Package Manager to load, type "PagedList.MVC" in the "Search Online" box in the top right of the package manager, and then select the "PagedList.MVC" package authored by Troy Goode and install it.
- Integrate the CSS that gets deployed with the PagedList.MVC nuget package. As Troy covers in the documentation on his GitHub page, the NuGet package will drop a PagedList.css file into the Content folder of your MVC app. Either move that around, bundle it, or integrate it elsewhere as needed (you might not need it if you're already using Bootstrap), and make sure your pages include the styling needed to style paging details.
- Add Optional page and pageSize Parameters to your Controller for your Paged ActionResult. See below.
Instead of handing back an IEnumerable
, pass back an IPagedListMake sure to pass in the page and pageSize parameters and this object now has all the information it needs to adequately page your data in your output or display. .
- Throw out an @Html.PagedListPager() into your markup. This customized HtmlHelper method does a fantastic job of cleanly outputting markup based on the current status of your paged list. There are also a handful of useful overloads that make it insanely easy to extend.
To better put this into perspective, assume I've got the following code, which returns 50+ results that are just handed out to my current view and displayed as one long, scrollable, list of results:
After dropping in the PagedList.Mvc NuGet package and wiring up CSS, I'd end up with a method where I'm now passing a PagedList
In my view, I'll also have to change my @model declaration as well. Prior to adding paging my @model would have looked like this:
After paging, it'll look like this:
The beauty of this is that both List and PagedList are just implementations of IEnumerable
All you need to do from here is to drop an @Hmtl.PagedListPager() into the mix. Doing so can be pretty simple to start with, because all you need is an action or page to return to, along with a means of expressing which page you're currently on. Optionally, you can also define how big your pageSize is. You can tweak or set via a drop down somewhere on your page that lets users to set this value themselves:
As you can see, the @Model, as a PagedList
Scratching the Surface
The best part is that I've only scratched the surface of what this solution can do. Additional information on how to style or control pager output can be found on the main site, or by simply testing and poking around with various overloads and options; I found the usage of this solution to be very intuitive.