Simple Sort Enabled Paginated ASP Table

I don’t do a lot of web development, certainly when I do it’s in PHP running in Apache and not C# ASP in IIS. But recently I had to build some tools in ASP using C# to replace my older Python/Apache site. I am learning as I go; although, I have done things in the past so it is not as painful as it could be. I would imagine a day to day C# ASP developer will laugh at this. Please be nice!

So it’s going pretty good then I decided to allow users to sort large tables, which I had already paginated. I was amazed at how easy this was to implement. It took some trial and error, I won’t lie, and no this will not move me away from PHP 🙂

Since I noticed people asking I thought I would share. I am not using MVC as these are very straight forward utilities only being used by a few people and developed\maintained by an individual.

In the ASP page add the gridview. It will need to run as server, of course, and set to paginate and sort. The method names are set so copy paste should work. Here’s the ASP:

<asp:GridView Width="100%" ID="ADGroupMembers" AllowSorting="true" OnSorting="ADGroupMembers_Sorting" AllowPaging="true" OnPageIndexChanging="OnPagingChange" PageSize="10" runat="server">
    <AlternatingRowStyle BackColor ="#f0f0f0" />
    <PagerSettings Mode="NumericFirstLast" Position="Bottom" PageButtonCount="5" NextPageText=">>" PreviousPageText="<<" />
    <PagerStyle CssClass="pager-row" />
</asp:GridView>

This is the method that populates the gridview in the code behind. In this case I am executing this from a drop down list of particular Active Directory groups in order to list the members of the selected group.

/* 
I populate fromva dropdown of groups I care about then onChange execute this method to populate the gridview.
This data could be anything from anywhere.
*/
protected void GetMembers(string groupName) {
    using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
    {
        using (GroupPrincipal gp = GroupPrincipal.FindByIdentity(ctx, groupName))
        {
            if (gp != null)
            {
                // Create datatable and headers...
                DataTable table = new DataTable();
                
                table.Columns.Add("ID", typeof(string));
                table.Columns.Add("Name", typeof(string));
                table.Columns.Add("Emp ID", typeof(string));
                table.Columns.Add("Department", typeof(string));
                table.Columns.Add("Manager", typeof(string));

                // Get our AD data.
                foreach (Principal p in gp.GetMembers())
                {
                    UserPrincipal up = p as UserPrincipal;

                    // yes this is messy...
                    if (up != null)
                    {
                        string department = "";
                        string manager = "";
                        
                        // This should be separate but I am lazy... Will refactor eventually :)
                        var dproperty = "department";
                        var directoryEntry = p.GetUnderlyingObject() as DirectoryEntry;
                        if (directoryEntry.Properties.Contains(dproperty))
                        {
                            department = directoryEntry.Properties[dproperty].Value.ToString();
                        }

                        var mproperty = "manager";
                        if (directoryEntry.Properties.Contains(mproperty))
                        {
                            manager = directoryEntry.Properties[mproperty].Value.ToString();
                        }

                        DataRow row = table.NewRow();

                        row["ID"] = up.SamAccountName;
                        row["Name"] = up.DisplayName;
                        row["Emp ID"] = up.EmployeeId; // I assume this will become the cn/sam,principal ID in the future.
                        row["Department"] = department;

                        string mgr_name = "";
                        if (!string.IsNullOrEmpty(manager)) {
                            UserPrincipal mgr = UserPrincipal.FindByIdentity(ctx, IdentityType.DistinguishedName, manager);
                            mgr_name = mgr.DisplayName;
                        }

                        row["Manager"] = mgr_name;

                        table.Rows.Add(row);
                    }
                }

                table.DefaultView.Sort = "ID Asc"; // initial sort...
                ADGroupMembers.DataSource = table;
                ADGroupMembers.DataBind();
                
                // Here's the magic. 
                Session["objects"] = table;
                ViewState["sort"] = "Asc";
            }
        }
    }
}

This method will paginate the data.

// Handle the table pagination.
protected void OnPagingChange(Object sender, GridViewPageEventArgs e)
{
    ADGroupMembers.PageIndex = e.NewPageIndex;
    ADGroupMembers.DataSource = Session["objects"];
    ADGroupMembers.DataBind();
}

Here is the method to handle the sorting.

// Handle the sorting.
protected void ADGroupMembers_Sorting(object sender, GridViewSortEventArgs e)
{
    DataTable sortedView = (DataTable)Session["objects"];

    if (sortedView.Rows.Count > 0)
    {
        if (Convert.ToString(ViewState["sort"]) == "Asc")
        {
            sortedView.DefaultView.Sort = e.SortExpression + " Desc";
            ViewState["sort"] = "Desc";
        }
        else
        {
            sortedView.DefaultView.Sort = e.SortExpression + " Asc";
            ViewState["sort"] = "Asc";
        }

        Session["objects"] = sortedView;
        ADGroupMembers.DataSource = sortedView;
        ADGroupMembers.DataBind();
    }
}

That’s it! That’s all there was to it.