Most line of business ASP.NET applications rely heavily on some form of Data Table / Data Grid component. These components take either lists of strongly typed objects or an instance of a DataTable and display the contents in a tabular format. The grid components provide common functionality such as sorting, filtering and paging. While these components are intended to help the developer by encapsulating this common logic, they also tend to be a major road-block to updating the application. This happens because often the implementation of the grid component requires us to provide the data in a very specific way which leads to high coupling.
In the case of BugTracker, we are lucky in a way because it does not use a third party grid library. Unfortunately, the custom implementation of grids still makes it very difficult to change in some places.
The Current Approach
Let's start with a very simple example from the Admin section. The Admin -> Projects page displays all of the projects defined in BugTracker in a simple, sortable grid.
The original Projects grid
From a user interface perspective, this grid is functional but a visually not very appealing. I would like to give it a more modern look and feel.
More importantly, there are a number of things I would like to improve regarding the implementation of this grid. Rendering this grid involves passing the Response object and a DataSet to a static method called SortableHtmlTable.create_from_dataset. This method contains a lot of code along the lines of:
There are some big assumptions made in this code. If we want to disable sorting for a column, we need the column name to start with $no_sort_. The code above only represents the portion of the code that deals with rendering the header. The code for rendering the rows of data is equally complex and also riddled with assumptions about the contents of the dataset.
In order of this mechanism of rendering a grid to work, the projects.aspx page executes some strange looking SQL:
Notice how there is HTML embedded inside this query. In order to have display edit/delete links, we need the cells in the data set to contain the actual HTML that will be rendered on the client.
This approach is difficult to maintain because the intention is not clear. User Interface concerns such as displaying links to other pages would be best managed by the aspx page. It is also inefficient. Instead of just retrieving the id from the database server, we are sending HTML to the database server in the form of a longer than necessary query, then asking it to send that HTML back for each row so the web server can send that HTML back to the client.
There is a ton of room for improvement here, but first let's start by finding an existing data grid control that we can use.
Selecting a Grid Control
I have had very good luck with DataTables, a data table plug-in for jQuery. Note that this is not strictly an ASP.NET control. It is a client-side jQuery based control that can be used with any server-side web framework. It is a very capable, flexible, fast and extremely well document option for adding rich data grid functionality to any web application.
Let's start by adding DataTables to our project.
DataTables has a number of options of how to initialize the grid. For example, we can retrieve the data via Ajax or we can have the server render a simple HTML table then tell DataTables to convert that HTML table element into a fully featured data grid.
For the simple grids in BugTracker, we will opt for rendering the HTML table on the server. This option will fit nicely with the Layered approach that we discussed in the Styles of Web Forms section.
Updating the Projects grid
Let's start by rendering the HTML table element in projects.aspx.
We will replace
with the following code that is a little more verbose but conveys the intention much more clearly:
Now that the Edit / Delete / User Permissions links are rendered clearly in the aspx page, we can simplify our SQL in the code behind.
After applying some Bootstrap styling and layout, our new Projects grid looks like this:
Projects grid using DataTables.NET
We have moved the row actions for edit, user permissions and delete to the last column and changed them to more modern looking icons. By default, the DataTables component gives us column sorting with nice sort indicator icons. We also get Paging and Searching for free. While these feature might seem like overkill when the grid only has 2 rows, it will be nice to get these features across the board.
We now have a modern grid component that provides a better UI and we have greatly simplified the code related to displaying the grid.
We can simplify this code even further by using the new Entity Framework model that we recently introduced. This eliminates the SQL in the code behind:
On the aspx page, we can now loop over the strongly typed array of Project objects which further simplifies the code:
You might be wondering about the performance of this approach and how well it will scale when dealing with large amounts of data. These are valid concerns as this approach has the potential to be very inefficient if we are trying to display a large number of rows.
For the example above, performance should not be a problem. I can't imagine a situation where we would have more than a handful or projects in the system and I know that this approach will scale well to at least 100 rows. However, it is always a good idea to test these types of assumptions. I decided to create 1000 projects in the database and see how BugTracker handled it.
From a server performance, this seems to perform within acceptable parameters. The HTML that is generated comes in at just over 1MB. This is a little on the large side for sure, but by default IIS on my local developer machine is actually compressing that HTML before sending it to the client. The actual size of the package delivered to the client is only 73.8KB. I can live with these parameters as a worst case scenario.
Response size with 1000 projects
One thing I did notice is that the grid flashes momentarily before the DataTables component is initialized. This can be annoying to the user. An easy solution to this is to hide the table initially, then show the table only after DataTables is done initializing. While the table is initializing, we will show some loading text so the screen is not blank for the user.
This small change will ensure a good user experience for a fairly large number of rows. We can be confident at least that all the admin grids will work using this approach.
According to guidance provided on the DataTables.net FAQ, this DOM sourced data approach should scale to ~5,000 rows. That seems a little high to me but again gives me confidence that we will be okay for the simple admin grid.
In the next post, we will turn our attention to the far more complex Bugs grid.