ASP.NET 1.x has an extremely flexible and
generic data-binding architecture that gives developers full control of
the page life cycle. Developers can link data-bound controls such as
the DataGrid to any enumerable
collection of data. While this approach represents a quantum leap from
classic ASP, it still requires page developers to learn a lot of
architectural details to create even relatively simple read-only pages.
This is a problem for Web developers with limited skills because they
soon get into trouble if left alone to decide how (or whether) to
implement paging, sorting, updates, or perhaps a master/detail view.
But this is also a (different) problem for experienced developers, as
they have to continually re-implement the same pattern to access data
sources, get data, and make the data consistent with the programming
interface of data controls.
The key issue
with ASP.NET 1.x data binding is a lack of a higher-level and possibly
declarative model for data fetching and data manipulation. As a result,
an ASP.NET 1.x data access layer is boring to write and requires
hundreds of lines of code even for relatively simple scenarios. Enter
ASP.NET data source components.
1. Overview of Data Source Components
A
data source component is a server control designed to interact with
data-bound controls and hide the complexity of the manual data-binding
pattern. Data source components not only provide data to controls, they
also support data-bound controls in the execution of other common
operations such as insertions, deletions, sorting, and updates. Each
data source component wraps a particular data provider—relational
databases, XML documents, or custom classes. The support for custom
classes means that you can now directly bind your controls to existing
classes—for example, classes in your business or data access layer.
(I’ll say more about this later.)
Existing
ASP.NET 1.x controls have been extended in ASP.NET 2.0 and newer
versions to support binding to data source controls as far as data
retrieval is concerned. The DataSourceID
property represents the point of contact between old-style data-bound
controls and the new data source components. Starting with ASP.NET 2.0,
you can successfully bind a DataGrid to a data source control without writing a single line of code—not even the ritual call to DataBind. However, achieving codeless programming is not the primary goal of
data source controls. Think of data source controls as the natural tool
to achieve a less complex and semi-automatic interaction between a
variety of data sources and controls.
Existing controls such as DataGrid and Repeater don’t take full advantage of data source components. Only controls introduced with ASP.NET 2.0 such as GridView, FormView, and DetailsView (plus the ListView
control in ASP.NET 3.5) benefit from the true power of data source
controls. This is because new controls have a different internal
structure specifically designed to deal with data source controls and
share with them the complexity of the data-binding pattern.
A Click in the Life of DataGrid
To
understand the primary goal of data source components, consider what
happens when the user performs an action on some data displayed through
a DataGrid. Imagine you display an
editable grid—that is, a grid that contains an edit column. Users click
a cell to edit the corresponding row; the DataGrid posts back and fires an event. Page authors handle the event by writing some code to switch the DataGrid
control to edit mode. A pair of OK/Cancel buttons replace the edit
button. The user edits the contents of the row and then clicks to save
or cancel changes. What happens at this point?
The DataGrid control captures the event, validates the user-provided data, and then fires the UpdateCommand
event. The page author is in charge of handling the event, collecting
new data, and building and running any required command against the
data source. All these steps require code. The same thing happens if
you need to sort data, view a new page, or drill down into the
currently selected record.
A Click in the Life of GridView
Let’s see what happens if you use the successor to the DataGrid control—the GridView
control—which is specifically designed to adhere to the data source
model. Let’s assume the same scenario: the user clicks, and the control
enters edit mode. The first difference is that you don’t need to write
any code to turn on the GridView’s
edit mode. If you click on a cell within an edit column, the control
“knows” what you want to do and intelligently takes the next step and
executes the requested action—turning on the edit mode.
When the user clicks to save changes, again the GridView
control anticipates the user’s next action and talks to the data source
control to have it perform the requested operation (update) on the data
source. All this requires no code from the page author; only a few
settings, such as the command text and the connection string, are
required and they can be set declaratively.
The
combination of data source controls and new, smarter data-bound
controls shows off its true power when your code addresses relatively
common scenarios, which it probably does 70 to 80 percent of the time.
If you need to have things done in a particular way, just work the
old way and take full control of the page life cycle. This said, you’ll
find that data source controls have much more than just a deep
understanding of the page life cycle. Data source controls support
declarative parameters, transparent data caching, server-side paging
ability, hierarchical data support, and the ability to work
asynchronously. Implementing all these features manually would require
quite a bit of code.
2. Internals of Data Source Controls
A
data source control represents one or more named views of data. Each
view manages a collection of data. The data associated with a data
source control is managed through SQL-like operations such as SELECT,
INSERT, DELETE, and COUNT and through capabilities such as sorting and
paging. Data source controls come in two flavors—tabular and
hierarchical. Tabular controls are described in Table 1.
Table 1. Tabular Data Source Controls
Class | Description |
---|
AccessDataSource | Represents a connection to a Microsoft Access database. Inherits from the SqlDataSource control, but points to an MDB file and uses the Jet 4.0 OLE DB provider to connect to the database. |
LinqDataSource | Allows
binding to the results of a Linq-to-SQL query. The control offers
properties for you to specify the data context, table name, projection
parameters, and where clause. This control is supported only in ASP.NET 3.5. |
ObjectDataSource | Allows
binding to a custom .NET business object that returns data. The class
is expected to follow a specific design pattern and include, for
example, a parameterless constructor and methods that behave in a
certain way. |
SqlDataSource | Represents
a connection to an ADO.NET data provider that returns SQL data,
including data sources accessible through OLE DB and ODBC. The name of
the provider and the connection string are specified through properties. |
Note that the SqlDataSource class is not
specific to SQL Server. It can connect to any ADO.NET provider that
manages relational data. Hierarchical data source controls are listed
in Table 2.
Table 2. Hierarchical Data Source Controls
Class | Description |
---|
SiteMapDataSource | Allows
binding to any provider that supplies site map information. The default
provider supplies site map data through an XML file in the root folder
of the application. |
XmlDataSource | Allows binding to XML files and strings with or without schema information. |
Note
that data source controls have no visual rendering. They are
implemented as controls to allow for “declarative persistence”
(automatic instantiation during the request processing) as a native
part of the .aspx source code and to gain access to the page view state.
Data Source Views
A named view is represented by a data source view object—an instance of the DataSourceView
class. These classes represent a customized view of data in which
special settings for sorting, filtering, and other data operations have
been defined. The DataSourceView
class is the base class for all views associated with a data source
control. The number of views in a data source control depends on the
connection string, characteristics and actual contents of the
underlying data source. In ASP.NET 2.0 and newer versions, built-in
data source controls support only one view, the default view. Table 3 lists the properties of the DataSourceView class.
Table 3. Properties of the DataSourceView Class
Property | Description |
---|
CanDelete | Indicates whether deletions are allowed on the underlying data source. The deletion is performed by invoking the Delete method. |
CanInsert | Indicates whether insertions are allowed on the underlying data source. The insertion is performed by invoking the Insert method. |
CanPage | Indicates whether the data in the view can be paged. |
CanRetrieveTotalRowCount | Indicates whether information about the total row count is available. |
CanSort | Indicates whether the data in the view can be sorted. |
CanUpdate | Indicates whether updates are allowed on the underlying data source. The update is performed by invoking the Update method. |
Name | Returns the name of the current view. |
The CanXXX
properties indicate not only whether the data source control is capable
of performing the specified operation but also whether that operation
is appropriate given the current status of the data. Table 4 lists all the methods supported by the class.
Table 4. Methods of the DataSourceView Class
Method | Description |
---|
Delete | Performs a delete operation on the data associated with the view |
Insert | Performs an insert operation on the data associated with the view |
Select | Returns an enumerable object filled with the data contained in the underlying data storage |
Update | Performs an update operation on the data associated with the view |
All data source view objects support data retrieval through the Select method. The method returns an object that implements the IEnumerable interface. The real type of the object depends on the data source control and the attributes set on it.
Interaction with Data-Bound Controls
Figure 1 shows the interaction between a data source control and data-bound control in ASP.NET 2.0 and newer versions.
Most ASP.NET controls are aware of the full potential of data source controls, and they use the methods of IDataSource
to connect to the underlying data repository. Implementing the
interface is the only official requirement for a control that intends
to behave like a data source control. Once it gets a hold of a data
source view object, the control can call the properties and methods
shown earlier in Table 3 and Table 4 to perform required tasks.
Hierarchical Data Source Views
Unlike
tabular data source controls, which typically have only one named view,
hierarchical data source controls support a view for each level of data
that the data source control represents. Hierarchical and tabular data
source controls share the same conceptual specification of a consistent
and common programming interface for data-bound controls. The only
difference is the nature of the data they work with—hierarchical vs.
flat and tabular.
The view class is different and is named HierarchicalDataSourceView. The class features only one method—Select—which returns an enumerable hierarchical object. Hierarchical data source controls are, therefore, read-only.