CoverStory
LANGUAGES: C# | VB.NET
ASP.NET VERSIONS: 2.0
Size Matters
Minimize Code with the ObjectDataSource Control
By Dan Wahlin
With the release of .NET version 2, Web application development has become more productive than ever especially when it comes to building highly scalable, data-driven Web applications. Many new server controls and framework classes added into version 2 of the framework make the process of generating dynamic Web pages less code-intensive and much simpler. Why does that matter? It s really very simple: less code leads to fewer bugs, easier maintenance, and greater overall productivity.
In addition to all the fantastic ASP.NET server controls being released in version 2 of the framework, there are also five new data source controls. These controls include SqlDataSource, XmlDataSource, AccessDataSource, SiteMapDataSource, and ObjectDataSource. By using data source controls in your ASP.NET Web Forms you can significantly minimize the amount of code needed to gather data and bind it to server controls, such as the new GridView or DetailsView controls. In this article I ll focus on the ObjectDataSource control and demonstrate how it can be used to tie presentation code to business layer code with a minimal amount of effort.
Why Use the ObjectDataSource Control?
I m a big fan of the n-tier architecture model, where presentation, business, and data layers are separated into logical tiers for greater code re-use and more flexibility when it comes to future code changes (see Figure 1). With the release of the ObjectDataSource control, hooking the presentation tier to the business tier is easier than ever and in many cases can be done without writing a single line of code.
Figure 1: An n-tier architecture model provides for better code re-use and helps
isolate the presentation tier from other tiers, such as the data tier. This
provides for a more loosely coupled system.
The ObjectDataSource control can be utilized by dragging and dropping it from the Visual Studio.NET 2005 (or Visual Web Developer 2005) toolbox onto an ASP.NET Web Form. Those who prefer to enter code manually can enter into the source code editor code similar to this:
SelectMethod="GetCustomers"
TypeName="BAL" DataObjectTypeName="Customer" /> The ObjectDataSource data source control works by using
reflection to load a specific object (BAL in the code shown above), and then
call one or more of its member methods. While this may raise a red flag to some
because reflection relies on late-bound operations, performance is quite good
in the non-scientific tests I ve run. Obviously you ll want to test it within
the context of your application to ensure that it meets performance
expectations. Selecting a business object that the ObjectDataSource
control can utilize is most easily accomplished by using the built-in wizard
available in the various 2005 development environments (see Figure 2). The
wizard makes selecting objects and methods a snap and requires no code to be written.
Methods can be chosen for select, insert, update, and delete operations. After a business object and associated methods have been
assigned to the ObjectDataSource, it can be used as a data source for server
controls such as the DropDownList, GridView, DetailsView, and others. The
following code shows how a GridView control s DataSourceID property can be used
to refer to an ObjectDataSource control named odsCustomers (the GridView
control replaces the DataGrid control found in ASP.NET 1.1): DataSourceID="odsCustomers" /> By referencing the data source control, the GridView
control will automatically be populated with any available data without writing
additional code. Data binding was quite straightforward in .NET version 1.1,
but you can see that it s even easier in version 2 even when data must be
obtained from business or data tier code. Now that you ve seen some of the fundamentals of the
ObjectDataSource control, let s see how it can be put to use to tie together different
code tiers. First we ll need to write business and data tier classes that
handle business rules and data access, respectively. Figure 3 shows a method
named GetCustomers in a data tier class named DAL. This method calls a SQL
Server stored procedure that returns as an array of Customer objects all
customers in the Northwind database s Customers table. Each customer object is
created and filled by calling another method named FillCustomer. The Customer
object contains basic properties such as CustomerID, ContactName, City, and PostalCode,
plus a few others. public static Customer[] GetCustomers() { Customer[] custs = null; DbConnection conn = null; DbDataReader reader =
null; try { conn =
GetConnection("NorthwindConnStr"); conn.Open(); DbCommand cmd =
conn.CreateCommand(); cmd.CommandText =
"GetCustomers"; cmd.CommandType =
CommandType.StoredProcedure; reader =
cmd.ExecuteReader(); custs =
FillCustomer(reader); } catch (Exception exp) { HttpContext.Current.Trace.Warn("Error", "Error in
GetCustomers: " + exp.Message); return null; } finally { if (conn != null)
conn.Close(); if (reader != null)
reader.Close(); } return custs; } private static DbConnection GetConnection(string connStrName) { ConnectionStringSettings
s = ConfigurationManager.ConnectionStrings[connStrName]; DbProviderFactory f = DbProviderFactories.GetFactory(s.ProviderName); DbConnection conn =
f.CreateConnection(); conn.ConnectionString =
s.ConnectionString; return conn; } private static Customer[] FillCustomer(DbDataReader reader) { List while (reader.Read()) { Customer cust = new
Customer(); cust.Address =
reader["Address"].ToString(); cust.City =
reader["City"].ToString(); cust.CompanyName =
reader["CompanyName"].ToString(); cust.ContactName =
reader["ContactName"].ToString(); cust.ContactTitle =
reader["ContactTitle"].ToString(); cust.Country =
reader["Country"].ToString(); cust.CustomerID =
reader["CustomerID"].ToString(); cust.Fax =
reader["Fax"].ToString(); cust.Phone =
reader["Phone"].ToString(); cust.PostalCode =
reader["PostalCode"].ToString(); cust.Region =
reader["Region"].ToString(); custList.Add(cust); } return
custList.ToArray(); } Figure 3: The
GetCustomers method handles all data access functionality and returns to the
caller a resultset containing customer records. The GetCustomers method shown
here is a member of a data tier class named DAL (data access layer). Another method named GetConnection is also shown in Figure
3 to demonstrate using the new DbProviderFactory class found in .NET version 2.
Although a complete discussion of this class and its related classes is beyond
the scope of this article, in a nutshell, the DbProviderFactory class allows
generic data access code to be written that isn t tied to a specific database
vendor such as Microsoft or Oracle. In addition to using the DbProviderFactory
class, the GetConnection method in Figure 3 also shows how to access the new After the data access layer code is written, a business
tier class is needed to call the GetCustomers method found within the data
tier. Figure 4 shows a simple business tier method named GetCustomers that is a
member of a class named BAL. Although quite simple, GetCustomers could include
business rules required by the application, such as filtering or caching rules. public static Customer[] GetCustomers() { return
DAL.GetCustomers(); } Figure 4: The
GetCustomers method shown here is a member of the BAL class (business access
layer) that handles business tier code execution. Now that the business and data tier code has been written
to select customers from the Northwind database, the ObjectDataSource can be
combined with the new GridView server control to easily hook up the presentation
tier to the business tier and display customers to end users. By mousing over
the ObjectDataSource control while in design-mode in Visual Studio.NET 2005 (or
Visual Web Developer 2005), the new smart tag functionality will appear as
shown in Figure 5. By selecting Configure Data Source the BAL business class
can be selected, as well as the GetCustomers method (refer back to Figure 2 for
an example of the ObjectDataSource wizard). To this point you ve seen how records can be selected
using a tiered architecture and the ObjectDataSource control. However, nothing
has been mentioned about performing insert, update, or delete operations. Fortunately,
adding this functionality isn t too difficult. First, the appropriate methods
must be added to the data and business tier classes. The sample code included
with this article defines DeleteCustomer, UpdateCustomer, and InsertCustomer
methods within each tier s class. Performing update and delete operations is extremely easy
using the GridView control along with the ObjectDataSource control. However,
inserting records ended up requiring more code than I thought necessary, so I
combined the GridView control with the DetailsView control because the
DetailsView control is designed to handle update, delete, and insert operations
directly. If you re unfamiliar with the DetailsView control, it s
used to display one record at a time and allows an end user to modify the
record if desired. An example of using it to edit a record is shown in Figure
6. Because two controls are being used to display data
(GridView and DetailsView), two ObjectDataSource controls are needed. The first
selects all customer data and passes it to the GridView control for display. Once
a user selects a record within the GridView, the second ObjectDataSource
control grabs the proper customer data based on the CustomerID selected in the
GridView and displays the customer data using the DetailsView control. The second ObjectDataSource control also allows the
selected record in the DetailsView control to be updated, deleted, or inserted
by calling into the business tier class methods. These operations are made
possible by using the ObjectDataSource wizard (again, refer to Figure 2) and
require virtually no code to be written. In fact, by using only the GridView,
DetailsView, and ObjectDataSource controls, a minimal amount of presentation
tier code has to be written, which handles refreshing the GridView control as
each record s data is changed. A portion of this code is shown below: //Refresh GridView when DetailsView control (dvCustomer) //insert event is fired so that new record displays. protected void dvCustomer_ItemInserted(object sender, DetailsViewInsertedEventArgs e) { this.gvCustomers.DataBind(); } Using the ObjectDataSource control will allow you to focus
on the important parts of your application and not worry as much about hooking
up the presentation and business tiers. This should lead to a reduction in
development time, less bugs, and, ultimately, happier customers. The
ObjectDataSource control certainly isn t perfect for every situation where an
ASP.NET Web Form needs to consume business tier data; I ve run into several
instances where I had to work outside the normal bounds of the control and
write additional code to support it. However, when used appropriately, it can
definitely jumpstart your ASP.NET 2.0 application development projects. The sample code
accompanying this article is available for download. Dan Wahlin
(Microsoft Most Valuable Professional for ASP.NET and XML Web services) is the
president of Wahlin Consulting, as well as a .NET instructor at Interface
Technical Training. Dan founded the XML for ASP.NET Developers Web site (http://www.XMLforASP.NET), which focuses
on using XML, ADO.NET, and Web services in Microsoft s .NET platform. He s also
on the INETA Speaker s Bureau and speaks to .NET User Groups around the US.
Dan co-authored Professional Windows DNA
(Wrox), ASP.NET: Tips, Tutorials, and Code
(SAMS), and ASP.NET 1.1 Insider Solutions,
and authored XML for ASP.NET Developers
(SAMS).
Figure 2A: The ObjectDataSource
control wizard allows objects and methods to be selected quickly and easily
without writing code. This image shows how a business object can be selected.
Figure 2B: This image shows how methods
within a business object can be used to perform various CRUD operations. Creating Business and Data Tiers
Figure 5: The new smart tag
functionality found in the 2005 developer tools allows easy access to an object s
functionality. This example shows how to access the ObjectDataSource s wizard
and select a business object and associated methods. Updating, Deleting, and Inserting Records
Figure 6: Editing records in a
database can be easily done by using the new DetailsView control. This example
shows how to use the GridView control to allow users to select a specific
record and then edit the record with the DetailsView control. Conclusion