WebGrid in MVC 3, step by step

One of the most common questions people ask me through my contact form, comments and in my MVC courses is how to implement datagrids with paging and sort order capabilities.

Since up to MVC 3 there wasn’t an official support to implement this feature from the platform itself, we were forced to manage by ourselves. We would either have to use the scaffolding generated by Visual Studio and develop manually the paging and the sort orders s (yuck!), or use external components (such as the MVCContrib, Telerik, jqGrid or others).

The latest ASP.NET MVC version, hand in hand with WebPages technology, brings us a new set of productivity helpers that are quite interesting in the namespaces System.Web.Helpers. Among them we find WebGrid, which finally offers a powerful and flexible default solution to help us implement this useful feature in our applications.

Let’s see, step by step and in a completely practical manner, how to use WebGrid.

1. First: the Model

The first thing we need before we begin to go in depth in the WebGrid helper is a Model, the app’s data entities as well as the tools that enables us to make persistant and recover the information from the storage system we are using.

In this case, we are going to use as a repository a SQL Express database with a single table, in which we have stored some people’s data; this collection is the one we want to display in a datagrid. Therefore, we have to fill it in with data to test it later.

In order to access the database we are going to use Entity Framework. To do so we are going to need an Entity Data Model (a conceptual entity model), which we can add to the project’s Models folder by selection the ”Add new item” option from the context menu. In the wizard that comes up, we only have to indicate it that we are going to generate the model from an exisiting database, and finally we select the table “People”. One we’ve finished this operation, we already have the basic data infrastructure for our application.

The next step is to create a services class, which provides the business logic and data access to our system. Obviously this does not always have to be this way, since it depends on our needs and the software’s architecture, and in our example both are going to be quite simple.

The starting code for our services class is as follows:

public class ModelServices: IDisposable {
   private readonly Entities entities = new Entities();
   public IEnumerable GetPeople()
   {
      return entities.People.ToList();
   }
   public void Dispose()
   {
       entities.Dispose();
   }
}

As you can see in the previous code, we have a single method called GetPeople(), which returns the complete set of people stored in the database.

And for now this is all the Model we need for the time being.

2. The controller

Our controller class, which we’ll call PeopleController, in this first approach is going to be really simple. A single action, Index(), which returns a view which we will supply the data collection obtained from the Model to:

public class PeopleController : Controller
{
    public ActionResult Index()
    {
        var data = new ModelServices().GetPeople();
        return View(data);
    }
}

An this is it: an action two lines. OK, it could have been performed in a single line, but this way the code is more readible ;-)

3. The View, take one: WebGrid comes into scene

Now it’s when we really begin to notice the advantages of using WebGrid versus other options available until MVC and that we have mentioned at the top of this post.

Look at the following code, a  Razor view that receives an number of Person objects form the controller and generates a complete grid:

@model IEnumerable<Person>
@{
    ViewBag.Title = "People";
    WebGrid grid = new WebGrid(Model);
}
<h2>People</h2>
@grid.GetHtml()

Impressing, isn’t it? Even though it seems incredible, the previous code is all we need to build a completely functional grid, with paging and column order: two lines! In the first line we instance the WebGrid providing it the data collection on which it has to iterate. In the second one we generate the HTML markup we’ll send to the client. The result of executing this code is displayed below:

Although it’s far from being perfect, the result is spectacular. The helper’s default behaviour displays a column for each property that it finds in the class on which it iterates, putting them in alphabetical order. In addition, it uses the name of the properties as column headings, and displays them as links to force the sort order by each one of them, and it even enters in the footer a complete data page navigation system. And the best thing is that all thid works directly, without having to add more code lines :-)

Nevertheless, as always, these automatisms have a cost. On one hand, we don’t control the columns to be displayed. Neither do we control the format in which its values are shown (see, for instance, the date of birth) nor their headings…

Normally we have to put in an extra effort (not much though) in order to leave everything perfectly. Moreover, there is a serious performance problem when the number of  grid elements is large:  both the sort order and the paging are performed on memory with the total number of items. Exagerating a bit, let’s suppose we have one million rows in the database, one million objects will materialize on memory, will be ordered according to the current criteria and, finally, only the ten objects that a data page contains are displayed to the client. Further on, we’ll see that there are some formulas to manage efficiently these scenarios.

[Learn MVC 4 step by step with the post author: 'Expert Web Development with ASP.NET MVC 4' created and tutored by Jose M. Aguilar]

4. The View, take two:  the columns I want, please

There are different formulas to specify the columns to be displayed in a WebGrid. The first of them is by exclusion on the total set of properties. Among many other aspects, we can specify in the GetHtml() method an array of name properties which mustn’t be shown as columns. For instance, taking the previous example, if we are interested in showing the PersonId property, we could have substituted the last line of the view for:


@grid.GetHtml(exclusions: new[] {"PersonId"})

However, the previous approach is not very useful, since want we generally want is to indicate the order in which the columns are displayed, specify their headers, determine whether or not the columns can be used as order criteria, etc. All this information is defined in WebGridColumn objects. Despite there are other ways of doing it, we habitually find in the columns parameter of the GetHtml() call an array with the detail of the grid columns, like in the following example:


@grid.GetHtml(columns: new [] {
    grid.Column("Name"),
    grid.Column("Surname"),
    grid.Column("EMail"),
    grid.Column("BirthDate"),
    grid.Column("Children")
})

As we can see, we are passing in the columns parameter an array in which each element is being generated by a call to the WebGrid Column() method, in which first parameter we indicate the name of the property  that the column corresponds to. The result of executing the code using this last code would be:

Somethings have improved, but we still have to tweak the way it is displayed.

5. The View, take three: the columns how I want, please

We still have to shore up several details for the grid to reach, at least visually, reasonable standards. To customize each column we can use the parameters form the Column() column generator method which we have seen above:

  • header, which allows to indicate the text shown in the header,
  • canSort, which indicates if the column can be used as sort order criteria,
  • format, which enables us to indicate a custom format for column content,
  • style, which indicates CSS class that will be applied to all the column cells.

Of all of the above, only the format property deserves a special mention. In it we can indicate, either through a Razor markup block or through the lambda function, how the content of the property vinculated to the column has to be formated. In the first case, we should start the markup block with the Razor escape character (@) and follow it with the code we want to send to the client. From inside we can make  reference to the object which is being evaluated by using @item, like in the following example, where how to format the EMail column so it is displayed as a mailto hyperlink:

    grid.Column("EMail",
                 format: @<a href="mailto:@item.Email">@item.Email</a>
    )

We can also use the lambda function, which receives as parameter the current item and returns a string (or a IHtmlString if it doesn’t have to be encoded). For instance, next we’ll see how to use this possibility to give format to the BirthDate column:

    grid.Column("BirthDate",
                format: p=>p.BirthDate.ToShortDateString()
    )

Therefore, bearing in mind all the above, we can tweak the grid a bit by using the following code. As a reminder, I’ll show the again the complete code of the view, so you can see how it results entirely:

@model IEnumerable<Person>
@{
    ViewBag.Title = "People";
    WebGrid grid = new WebGrid(Model);
}
<h2>People</h2>
@grid.GetHtml(columns: new [] {
    grid.Column("Name", canSort: false),
    grid.Column("Surname"),
    grid.Column("EMail",
                 format: @<a href="mailto:@item.Email">@item.Email</a>
    ),
    grid.Column("BirthDate",
                header: "Birth date",
                format: p=>p.BirthDate.ToShortDateString()
    ),
    grid.Column("Children",
                header: "Children",
                style: "to-the-right"
    )
})

In runtime we can see now how it’s almost finished:

6. The View, take four: And can’t I add custom columns?

Of course you can! In fact, you can do it by just adding columns like before, except that we don’t have to link them to any Model class property. This, combined with the flexibility of the custom format (format parameter), offers us everything we need to create columns the way we want to. The code below shows how to add an additional column with links to the actions that would enable it, for instance, to edit or delete a Person:

@grid.GetHtml(columns: new [] {
    ... // Rest of grid columns, seen previously
    grid.Column(
       "",
        header: "Actions",
        format: @<text>
                @Html.ActionLink("Edit",   "Edit",   new { id=item.PersonId} )
                |
                @Html.ActionLink("Delete", "Delete", new { id=item.PersonId} )
               </text>
    )
})

Notice how, to increase the code’s legibility, we are using the special Razor tag that allows us to create mark up blocks for several lines. The result is as follows:

7. The View, take five: I’d rather have it all as I want to

The WebGrid helper offers a bunch of extra customizing options that we can set when both calling it’s different methods or doing so directly. For instance GetHtml() enables us to indicate the following parameters, besides those that we have already studied:

  • headerStyle, footerStyle, rowStyle, alternatingRowStyle, and selectedRowStyle enable to indicate the CSS classes to apply to the header, footer, alternative data rows and selected row, respectively.
  • caption, to specify a title for a table, which will be included in a tag.
  • fillEmptyRows, set to true it makes each page have always the same number of rows, creating blank rows if needed.
  • emptyRowCellValue indicates the value to be shown in the empty row cells.
  • mode, enables specifying the type of paginator to be created, choosing it through a combination of elements of the WebGridPagerModes numbering:
    • WebGridPagerModes.Numeric: the pagainator shows all the direct links to pages near the current one.
    • WebGridPagerModes.FirsLast: links to go to the first or last data page are displayed.
    • WebGridPagerModes.NextPrevious: links to go to next or previous page are displayed.
    • WebGridPagerModes.All: all of the above at the same time.
  • numericLinksCount: indicates the number of pages that will appear whenever the mode contains the  WebGridPagerModes.Numeric value.
  • firstText, previousText, nextText, lastText, enables replacing the texts that appear by default in the go to first, previousm next and last page links respectively. Initially “<”, and “>>” is common.

For example, take a look at the following code and its runtime result once we have created a pair of rules in the web page style sheet:

<h2>People</h2>
<pre>@grid.GetHtml(
    fillEmptyRows: true,
    alternatingRowStyle: "alternative-row",
    headerStyle: "grid-header",
    footerStyle: "foot-grid",
    mode: WebGridPagerModes.All,
    firstText: "<< First",
    previousText: "< Previous", nextText: "Next >",
    lastText: "Last >>",
    columns: new [] {
     ... // column definition seen previously

})

Also, the WebGrid builder itself enables editing several functional aspects of the grid using the following parameters:

  • defaultSort, it indicates the column that will act as default order while no other one is specified.
  • rowsPerPage (by default, 10), defines the number of rows that appear on each page.
  • canPage, canSort, indicate respectively if the grid allows paging and sort order. By default it is set to true in both cases.
  • fieldNamePrefix, it enables indicating the prefix that is going to be used in the query string parameters used by the grid. This, for instance, will allow us to show several grids simultaneously on the same page, without interfering.
  • selectionFieldName, sortFieldName, sortDirectionFieldName enable indicating the name of the parameters used to keep the state of the selecetd row, the ordering field, and the direction of the ordering.

WebGrid even enables working in Ajax mode. In other words, it is able to display the different pages without loading the entire page. In this case, we can use the ajaxUpdateContainerId and ajaxUpdateCallback parameters, that allow us to indicate the element of the page where the data will be displayed and a callback function that will be called after updating the element.

Summarizing…

Throughout this post we have progressively analyzed the use of  WebGrid starting from a really simple example to more advanced custom scenarios. I hope this helps show the use and main features of this useful and powerful helper, which saves us a lot of time with our MVC3 projects.

Nevertheless, we have already stated that not all that glitters is not gold… The paging implemented by WebGrid by default is quite es very unefficient, since it has to have on memory the entire data set to order and extract only the requested page.  Implementing  this paging correctly is not a hard task. However, since this post is already very long, we’ll go over this issue in another post.

Here you can download the example used in this post.

[Learn MVC 4 step by step with the post author: 'Expert Web Development with ASP.NET MVC 4' created and tutored by Jose M. Aguilar]

Jose M. Aguilar

ASP.NET/IIS MVP

Jose M. is a well-known world expert in web technologies. He is the author of Microsoft Press SignalR Programming in Microsoft ASP.NET. He works as an independent consultant and developer, helping companies and institutions to reach their goals by using software. He also works with company development teams providing consultancy services and support in several fields. Follow Jose M on Twitter.

,

22 Responses to WebGrid in MVC 3, step by step

  1. upen September 27, 2012 at 10:50 #

    this is what i looking for,
    Thanks

  2. Norm October 17, 2012 at 03:26 #

    Great post! I’ve noticed by default the webgrid uses HttpGet. Does it have an HttpPost option? I’m trying to filter the contents of a webgrid but keep losing my search terms after the GET.

    • Jose M. Aguilar October 17, 2012 at 16:31 #

      Hi!

      I’m afraid not, WebGrid always uses GET because it uses links to navigate between pages and reorder the data. Probably, you could create an script to capture the clicks on these links and submit a form, but I don’t know if it would be a good idea.

      However, you can take advantage of this feature and add your own information to the querystring, as it is shown in this post: http://www.campusmvp.net/asp-net-mvc-webgrid-with-filtering-paging-and-sorting/.

      Hope it helps,
      Jose.

  3. Garrett January 4, 2013 at 00:05 #

    Hi Jose, thank you for the post. This is great stuff. I am new to programming, C#, and MVC3, and I would like to use this method. I just need to use it a little differently because I need to use a regular SQL database. I also need to figure out a way to take the data from this and put it into a chart. I’ve been able to create a chart statically from a stored procedure I’ve created, but not dynamically such as filtering on the UI side via checkboxes or drop-down lists. Any thoughts or suggestions would be greatly appreciated.

    • Jose M. Aguilar January 4, 2013 at 11:01 #

      Hi, Garret.

      First of all, thank you for commenting.

      If you need to use SQL commands, you should only change the implementation of the Model (the “M” in MVC). Thanks the separation of concerns proposed by this pattern, the controller (“C”) and the view (“V”) won’t be affected.

      Instead of using the class “ModelServices” as it is shown in this post, you should reimplement its methods using ADO classic (with classes such as SqlConnection or SqlDataReader) to get the data. Once you have read it from the database, you could instantiate a data entity, load its properties, and add it in a collection or list, that would be the result of the method. Thus, the controller would receive a list of data entities and its code would be the same.

      Regarding your second question, it’s only a question of presentation. Once your view have received all the data needed to generate the chart, you should choose the component in charge of represent it graphically. There are a lot of components, but you should take a look at the Chart helper included in MVC/Webpages, or at client solutions such as HighCharts.

      Best regards,
      Jose.

    • Nhan Nguyen March 19, 2013 at 15:46 #

      Good job!!!!!I like it very much. It’s helpful for me..

  4. Pouyan February 16, 2013 at 08:21 #

    You are awesome man … this is an impressive effort.

  5. vinay April 12, 2013 at 08:50 #

    This is really cool article , solution paging is really coll. i was looking for this every where..

  6. Srinu June 10, 2013 at 07:02 #

    Very nice article

  7. josh July 4, 2013 at 20:02 #

    nice work. there is another good example here.
    http://articlesforprogramming.blogspot.in/2013/07/webgrid-in-aspnet-mvc.html

  8. Fajeje July 25, 2013 at 10:24 #

    Thanks so much for the article Jose!
    May I know how can I customize column name? for example if the column name in table is
    ‘SureName’ and I wanna show it in WebGrid as ‘Family-Name’

  9. Fajeje July 25, 2013 at 11:08 #

    May I know where is the whole code for ModelServices?
    Thanks

    • Jose M. Aguilar July 25, 2013 at 11:19 #

      Hi, @Fajeje,

      First, you can customize the column’s header as it is shown in the example above, using the ‘header’ parameter in the column’s definition:

      grid.Column(“BirthDate”, header: “Birth date”, …)

      Regarding your second question, the full source code is downloadable through this url: http://www.campusmvp.net/wp-content/uploads/2012/05/WebGridDemo.zip.

      Best regards,
      Jose.

      • Fajeje July 25, 2013 at 12:01 #

        Thanks so much for reply.

        Simulating your great article, in step of implementing ModelServices I got this error:
        The type or namespace ‘Entities’ could not be found(are you missing a using directive or an assembly reference?)

        Visual Studio 2012 , installed EF, managed NuGet , added system.data.entity.design

        I need to simulate your project, emergency.
        Regards

        • Jose M. Aguilar July 25, 2013 at 12:33 #

          Hi again,

          “Entities” is only the name given to the data context class when it is generated by EF. So, if you don’t have it, create the database and follow the procedure shown in the first step to generate this class. Once done, remember to include a using directive to make this class visible where needed.

          If you are stuck, consider to download the full Project, where you’ll found this class and anything you’ll need to play with the example.

          Hope this helps

          • Fajeje July 26, 2013 at 06:15 #

            You are awesome. Please continue.
            I ve done it and need to decorate my application now. Thanks a looooot.

  10. Murat November 2, 2013 at 21:38 #

    Thank you very much for your perfect article. Actually there are lots of articles related to WebGrid, but only some of them contains lots of useful properties and tips at the same time.

    I have one problem regarding to WebGrid: I have tried to change many features especially my css classes, but I cannot align pager to right without aligning header text on the grid. Is it possible?

    On the other hand, is it possible to show first, next, previous and last link always. Have you ever tried or know if it is? Kindest regards.

    • Jose M. Aguilar November 2, 2013 at 21:54 #

      Hi!

      Yes, you can change the pager’s alignment using only CSS :)

      The method GetHtml(), as it is shown in this post, has a parameter called “FooterStyle” where you can specify the CSS class to be used on the footer. Then, in your stylesheet, you should only change the text-align to “right”.

      For example, if you have:

      @grid.GetHtml(
      fillEmptyRows: true,
      alternatingRowStyle: "alternative-row",
      footerStyle: "grid-footer",
      ...
      )

      Then, add the following rule to the CSS:

      .grid-footer {text-align: right; }

      … and that’s all :)

      Hope this helps.

      Regards,
      Jose.

  11. Neha February 5, 2014 at 14:38 #

    Thank you for your article. Actually I’m trying to display data from 4 tables together (the tables are related by foreign key!!). ok so I’ve not been successful doing that. Can you help me with that!?

Leave a Reply