One of my personal pet peeves is when I go to a conference or user group meeting and someone is doing a marketecture demo. That is, they are showing how something can be done, but are doing so in a manner that no self-respecting programmer would ever do in a production system of any magnitude. The speaker does this because it is easy to demo and looks slick, but inexperienced developer attendees often do not bridge the complexity gap in their heads and end up applying these unsound design principles when using the technology in their own projects at work.
Every new version of a Microsoft technology has a few canonical (yet principally unsound) demos that are nevertheless repeated over and over again ad nauseam. One of my least favorite examples from ASP.NET 2.0 is databinding using the new GridView Web control. In the typical demo, a GridView control is bound to a DataSetDataSource control. The presenter then shows how you can turn on features like sorting by just adjusting properties of the GridView control.
While the DataSetDataSource/GridView combination makes for a compelling whiz-bang demo, it shouldn't be used in a production system, because it reduces your application to a simple two-tier design that hasn't been popular since the client/server systems of the mid to late 90s. A better approach to the demo would be to bind the GridView control to the ObjectDataSource control. That gives you back your three-tier design, but the enhanced features of the GridView aren't quite as plug and play. They aren't terribly difficult to implement, though, if you know a few tricks. As an example, let me show you how to implement sorting in the ObjectDataSource/GridView combination scenario. You can download the complete source code for the demo, which I built using Visual Web Developer 2005 Express Edition Beta 1.
The objects in this demo are fairly simple in nature to ease the learning curve, but you'll see that adding more to them won't change the complexity of the implementation. The first thing that you need is an object and object collection to bind to. Listing 1 contains the definition for a simple Person class. I created the class in the special /Code subfolder of my Web project, but in a production scenario, you would likely want to move it into its own class library.
The Person class implements FirstName and LastName properties as well as a static GetPersonList method (eliminating the need to create an instance of the Person class to act as a broker). The GetPersonList method returns a PersonCollection object (Listing 2). I chose to create a PersonCollection type that internally uses generics to represent a collection of Person objects, but you could have just as easily specified a generic collection of Person objects as the return value of the GetPersonList method. It's a personal preference decision.
The GetPersonList method does most of the heavy lifting to enable sorting. The first thing that you will notice is that the method has a "sort" parameter. As you'll see in a moment, the GridView control collaborates seamlessly with the ObjectDataSource to pass information regarding the column that must be sorted as well as sort direction. The first part of the GetPersonList method creates a populated DataTable out of thin air. This part of the function is merely to make the demo more portable. In production, this would be where you placed code to fill a DataTable from your favorite data source (such as SQL Server).
Next, sort the DefaultView (a DataView object) of the populated DataTable based on the sort parameter passed into the GetPersonList method by the GridView control. The sort parameter will have a T-SQL compatible clause such as:
LastName
or
LastName DESC
As long as you set up the SortExpression attribute for each bound column in your GridView (Listing 3) to match a field in your DataTable, your data is sorted seamlessly. The only task remaining is to iterate the DefaultView and populate a PersonCollection with Person objects to pass back out from the GetPersonList method.
The UI implementation is a snap. Create a new Web Form and drop an ObjectDataSource control on the design surface. A smart tag will appear next to it, giving you the option to "Configure Data Source," which you should click. Select the Person class from the business object dropdown in the first screen of the wizard. On the next screen, select the GetPersonList method from the method dropdown. You don't need to do anything on the define parameters screen. Click Finish.
Drop a GridView control onto the design surface of your Web Form. Using the smart tag that pops up, select ObjectDataSource1 as the data source for the GridView. From the Properties window, change the AllowSorting property to True. You can modify the formatting of the grid (the AutoFormat options work well), but that isn't necessary.
The ASPX code for the GridView and ObjectDataSource control (Listing 3) show that each bound column has three attributes. The HeaderText attribute determines what the text at the top of the GridView column will be. The DataField attribute is the name of the item that the GridView column is bound to. In our case, this is the name of a property of the Person class. If you were binding to a DataSetDataSource, this would be a field name from a database table. The SortExpression attribute is the value that the GridView control will pass into the Sort parameter of the GetPersonList method when the column header is clicked (the "DESC" modifier is appended if this is the second time that you clicked the header and are requesting to sort the column in descending order).
In Listing 3, you can also see the TypeName, SelectMethod, and SortParameterName properties that were added by the Configure Data Source wizard. You can now run the page. Click the column headers to see how the grid sorts.
There may be occasions where you need to pass other parameters into your data gathering methods. For instance, you may need to pass in a security object. Listing 4 shows a simple SecurityContext object that implements UserID and Password properties. Add a Global.asax file to your project and in the Session_Start event, add code to store a SecurityContext object in session:
Session["SecurityContext"] = new
SecurityContext("JDG", "foo");
//Now, add an overload for the GetPersonList
//method to the Person class:
public static PersonCollection
GetPersonList(SecurityContext securityContext,
string sort)
{
//Don't do anything with SecurityContext.
//We just wanted to prove that we could pass it in
return GetPersonList(sort);
}
In this demo, you're not really going to do anything with the SecurityContext object, but it is helpful to demonstrate that you could do it if the need were to arise. To finish off the modified implementation, re-run the Configure Data Source wizard and when you get to the define parameters screen, add a SecurityContext parameter to the parameter list. Select Session on the Parameter Source dropdown and "SecurityContext" for the Session Field box. Click the Finish button. Just like that, you can use data stored in the client session state to help retrieve the data to display in your GridView control.
As you can see, implementing GridView sorting the right way, using a three-tier design and the ObjectDataSource control is not that difficult, lending credence to the power of the ASP.NET 2.0 provider model. Not everything is point and click, but if things get any easier, we're all going to be out of a job. My name is Jonathan Goodyear, and I am the angryCoder.