Sorting Data with Data Source Controls

You can display data in an ASP.NET Web page by using a data source control and a data-bound control. Some data controls let users sort the data without requiring any code.

If you want to enable users to sort data at run time, you can use a LinqDataSource, ObjectDataSource, SqlDataSource, or AccessDataSource control as the data source control. To display data that users can sort, you can use a GridView control or a ListView control.

Providing a User Interface for Sorting

You can create any user interface (UI) for sorting. However, the GridView and ListView controls provide a default UI sorting.

The GridView control supports sorting by a single column without requiring any programming. You set the AllowSorting property to true to automatically create the header text for each column as a link button that passes a sort expression to the data source control. You can further customize the sort functionality of the GridView control by handling the sort event. For more information, see Sorting Data in a GridView Web Server Control.

You can sort the data that is displayed in a ListView control by adding a button to the control's LayoutTemplate template and setting the button's CommandName property to "Sort". You set the CommandArgument property of the button to the column name that you want to sort by. Clicking the Sort button toggles the sort direction between Ascending and Descending. For more information, see ListView Web Server Control Overview and Walkthrough: Displaying, Paging, and Sorting Data Using the ListView Web Server Control.

Enabling Sorting in a Data Source Control

The data source controls that provide built-in support for sorting are the LinqDataSource, ObjectDataSource, SqlDataSource, and AccessDataSource controls. The LinqDataSource control supports sorting when the AutoSort property is set to true (the default), as in the following example:

<asp:LinqDataSource 
    ContextTypeName="ExampleDataContext" 
    TableName="Products" 
    AutoPage="true"
    AutoSort="true"
    ID="LinqDataSource1" 
    runat="server">
</asp:LinqDataSource>
<asp:GridView 
    AllowPaging="true"
    AllowSorting="true"
    DataSourceID="LinqDataSource1"
    ID="GridView1" 
    runat="server">
</asp:GridView>
<asp:LinqDataSource 
    ContextTypeName="ExampleDataContext" 
    TableName="Products" 
    AutoPage="true"
    AutoSort="true"
    ID="LinqDataSource1" 
    runat="server">
</asp:LinqDataSource>
<asp:GridView 
    AllowPaging="true"
    AllowSorting="true"
    DataSourceID="LinqDataSource1"
    ID="GridView1" 
    runat="server">
</asp:GridView>

The SqlDataSource and AccessDataSource controls support sorting only when their DataSourceMode property is set to DataSet (the default) as in the following example:

<asp:GridView ID="EmployeesGridView" 
  DataSourceID="EmployeesSqlDataSource" 
  DataKeyNames="EmployeeID" 
  AllowSorting="True"
  RunAt="Server" />

<asp:SqlDataSource ID="EmployeesSqlDataSource"  
  SelectCommand="SELECT EmployeeID, LastName, FirstName FROM Employees" 
  Connectionstring="<%$ ConnectionStrings:NorthwindConnectionString %>" 
  RunAt="server" />
<asp:GridView ID="EmployeesGridView" 
  DataSourceID="EmployeesSqlDataSource" 
  DataKeyNames="EmployeeID" 
  AllowSorting="True"
  RunAt="Server" />

<asp:SqlDataSource ID="EmployeesSqlDataSource"  
  SelectCommand="SELECT EmployeeID, LastName, FirstName FROM Employees" 
  Connectionstring="<%$ ConnectionStrings:NorthwindConnectionString %>" 
  RunAt="server" />

The ObjectDataSource control supports sorting if the object returned by the SelectMethod is a DataSet, DataTable, or DataView object. The ObjectDataSource also supports retrieving results in sorted order from the data source.

Custom Sorting

You can customize how sorting is performed by data-bound controls and data source controls. This enables you to modify how automatic sorting is performed or to create a custom sort routine.

When you use the LinqDataSource control, you can customize sorting by setting the AutoSort property to false. You can then create a handler for the Selecting event.

When you use the ObjectDataSource or SqlDataSource controls, you can take advantage of sorting capabilities by using the SortParameterName property. You can set the SortParameterName property to the name of the parameter that contains a sort expression being passed to the data source control. The sort expression is a comma-delimited list of fields to sort by (and optionally the DESC identifier to sort in descending order). For details about the format of the sort expression, see the DataView..::.Sort property.

The parameter identified by the SortParameterName property is passed to the ObjectDataSource control's SelectMethod or passed as part of the parameter collection to the SqlDataSource control's SelectCommand. The ObjectDataSource control can use the information passed to it in the sort parameter to return the data in sorted order. For the SqlDataSource control, you must supply the name of a stored procedure that can take the sort parameter and return the sorted data, because you cannot pass a parameter as part of an ORDER BY clause.

The following code example shows an ObjectDataSource control declaration that identifies a parameter named sortColumns as the sort parameter name:

<asp:ObjectDataSource 
  ID="EmployeesObjectDataSource" 
  runat="server" 
  TypeName="Samples.AspNet.Controls.NorthwindEmployee" 
  SortParameterName="SortColumns"
  EnablePaging="true"
  StartRowIndexParameterName="StartRecord"
  MaximumRowsParameterName="MaxRecords" 
  SelectMethod="GetAllEmployees" >
</asp:ObjectDataSource>
<asp:ObjectDataSource 
  ID="EmployeesObjectDataSource" 
  runat="server" 
  TypeName="Samples.AspNet.Controls.NorthwindEmployee" 
  SortParameterName="SortColumns"
  EnablePaging="true"
  StartRowIndexParameterName="StartRecord"
  MaximumRowsParameterName="MaxRecords" 
  SelectMethod="GetAllEmployees" >
</asp:ObjectDataSource>

The following code example shows a method in the source object for the ObjectDataSource control. The method is identified as the SelectMethod. The parameter identified by the SortParameterName property is used to sort the data retrieved from the database.

PublicSharedSub Initialize()    
  ' Initialize data source. Use "Northwind" connection string from configuration.If ConfigurationManager.ConnectionStrings("Northwind") IsNothingOrElse _
     ConfigurationManager.ConnectionStrings("Northwind").ConnectionString.Trim() = ""ThenThrowNew Exception("A connection string named 'Northwind' with a valid connection string " & _
                        "must exist in the <connectionStrings> configuration section for the application.")
  EndIf

  _connectionString = _
    ConfigurationManager.ConnectionStrings("Northwind").ConnectionString

  _initialized = TrueEndSub


' Select all employees.

<DataObjectMethod(DataObjectMethodType.Select, True)> _
PublicSharedFunction GetAllEmployees(sortColumns AsString, startRecord AsInteger, maxRecords AsInteger) As DataTable

  VerifySortColumns(sortColumns)

  IfNot _initialized Then Initialize()

  Dim sqlCommand AsString = "SELECT EmployeeID, LastName, FirstName, Address, City, Region, PostalCode FROM Employees "If sortColumns.Trim() = ""Then
    sqlCommand &= "ORDER BY EmployeeID"Else
    sqlCommand &= "ORDER BY " & sortColumns
  EndIfDim conn As SqlConnection  = New SqlConnection(_connectionString)
  Dim da   As SqlDataAdapter = New SqlDataAdapter(sqlCommand, conn) 

  Dim ds As DataSet =  New DataSet() 

  Try
    conn.Open()
    da.Fill(ds, startRecord, maxRecords, "Employees")
  Catch e As SqlException
    ' Handle exception.Finally      
    conn.Close()
  EndTryIf ds.Tables("Employees") IsNotNothingThen _
    Return ds.Tables("Employees")

  ReturnNothingEndFunction

'''''' Verify that only valid columns are specified in the sort expression to aSub a SQL Injection attack.PrivateSharedSub VerifySortColumns(sortColumns AsString)

  If sortColumns.ToLowerInvariant().EndsWith(" desc") Then _
    sortColumns = sortColumns.Substring(0, sortColumns.Length - 5)

  Dim columnNames() AsString = sortColumns.Split(",")

  ForEach columnName AsStringIn columnNames      
    SelectCase columnName.Trim().ToLowerInvariant()        
      Case"employeeid"Case"lastname"Case"firstname"Case""CaseElseThrowNew ArgumentException("SortColumns contains an invalid column name.")
    EndSelectNextEndSub
publicstaticvoid Initialize()
{
  // Initialize data source. Use "Northwind" connection stringfrom configuration.

  if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
      ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "")
  {
    thrownew Exception("A connection string named 'Northwind' with a valid connection string " + 
                        "must exist in the <connectionStrings> configuration section for the application.");
  }

  _connectionString = 
    ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

  _initialized = true;
}


// Select all employees.

[DataObjectMethod(DataObjectMethodType.Select, true)]
publicstatic DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords)
{
  VerifySortColumns(sortColumns);

  if (!_initialized) { Initialize(); }

  string sqlCommand = "SELECT EmployeeID, LastName, FirstName, Address, City, Region, PostalCode FROM Employees ";

  if (sortColumns.Trim() == "")
    sqlCommand += "ORDER BY EmployeeID";
  else
    sqlCommand += "ORDER BY " + sortColumns;

  SqlConnection conn = new SqlConnection(_connectionString);
  SqlDataAdapter da  = new SqlDataAdapter(sqlCommand, conn); 

  DataSet ds =  new DataSet(); 

  try
  {
    conn.Open();
    da.Fill(ds, startRecord, maxRecords, "Employees");
  }
  catch (SqlException e)
  {
    // Handle exception.
  }
  finally
  {
    conn.Close();
  }

  if (ds.Tables["Employees"] != null)
    return ds.Tables["Employees"];

  returnnull;
}


//////////// Verify that only valid columns are specified in the sort expression to avoid a SQL Injection attack.privatestaticvoid VerifySortColumns(string sortColumns)
{
  if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
    sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);

  string[] columnNames = sortColumns.Split(',');

  foreach (string columnName in columnNames)
  {
    switch (columnName.Trim().ToLowerInvariant())
    {
      case"employeeid":
        break;
      case"lastname":
        break;
      case"firstname":
        break;
      case"":
        break;
      default:
        thrownew ArgumentException("SortColumns contains an invalid column name.");
        break;
    }
  }
}

For more information, see Creating an ObjectDataSource Control Source Object.

See Also

Other Resources

Data Source Web Server Controls