ASP.NET Data Binding and Architecture

The architecture of your project can make or break it. It determines how fast you can add components, your dev time, time to fix bugs, etc. ThatDataGridIntroExample being said, one architecture component in particular I have struggled with is how to build the architecture for binding to data controls of an ASP.NET page. These types of controls include GridViews, Repeaters and FormViews to name a few. By struggled with, I mean not that it is a hard exercise to do by any means, but rather the opposite. It is so incredibly easy to bind information to these controls, and so many ways to do it. Which leads me to the problem:

Which binding method do I use for this project? Some methods provide greater functionality with decreased flexibility. Others provide great reusability with poor performance.

The following outlines what I consider to be the major 4 methods of ASP.NET control binding: Direct Binding, DataTables, XSD’s, and Custom Objects / DataReaders.

Example Notes: Attached here and at the end of the article is the example solution that demonstrates the very basic functionality and code of each binding method. Note that it is a Visual Studio 2008 Solution and project file:  Download BindingExamples Solutions . All screenshots and examples are used from this Solution. All pages have a final result of the screenshot above. SQL scripts and stored procedures found in this project as well.

Method 1: Direct Binding

When I say “Direct Binding”, what I am referring too is binding a GridView to an SqlDataSource which is in turn, bound directly to a stored procedure (or SQL query if you so choose). The markup code for this is nice and simple:

DirectBindingMarkup

The best thing about the direct binding method is its simplicity. Not only is there ZERO coding involved, but the Visual Studio Wizard will walk you right through the entire process from adding the SqlDataSource, to creating the query with the “Query Builder”. To begin the wizard… you can grab a GridView object from your toolbar throw it on the page and hover over it to get the click through arrow, and choose Configure Data Source:

DirectBindingWizard

After you have bound and configured your data source that is it, the GridView should now be working. So now lets spell out the good and bad of this method.

The Good:

  •  Super easy to setup and configure: This is something you could potentially setup and be pulling data in 5 min or less.
  • No Code: You have to write zero code for this method. All binding code is used directly from the Framework, only markup required.
  • Provides simplicity for allowing row deletion and editing (adding additional stored procedures / queries).
  • Paging and Sorting: Huge advantage to using a statically configured object data source is that you get out of the box paging and sorting (by simply enabling the property attribute on the GridView).

pagingsorting

The Bad:

  • Provides ZERO opportunity to write any business logic anywhere but in a Stored procedure.
  • Next to no flexibility for additional enhancments – it is what it is.
  • Paging and sorting is out of the box, however, keep in mind this is application side paging. Meaning the entire result set is retrieved from the database and then chopped, as opposed to only retrieving the results you needed from the database.
  • You have no reuseable data components or infrastructure after binding.

The Scoop: The idea of directly binding your gridviews (through object data sources) to a database is extremely nice for smaller projects that require a straight CREATE, UPDATE, DELETE and of course VIEW web interface. If the application is simply a means for input data, and you need to expose the data basically how it looks in the database, then this method might be the best for you. As well for small projects this is ideal since you can provide advanced viewing features like paging, sorting, theming, etc, very very fast and cost effectively to the client. The key is to keep in mind this solution provideds almost no flexibility for additional business logic or reuseability.

Method 2: DataTables

Binding a DataTable to a GridView is also quite easy. However, by using a DataTable you are given the advantage of being able to develop the source of the DataTable on your own. Its source could be a Database server, however, it could be something completely different. You could create a DataTable filled with information from your MembershipProvider API, or you may have a dynamic set of information to show. In these scenario’s you’ll have to create a DataTable and programmatically bind it to a GridView. This has the advantage of keeping your Business Logic separate from your Presentation Logic, which is a key design principle in larger scale applications.

Quick run through on how to do it… Once again you can throw a GridView control object onto your ASP.NET markup page. In this example you don’t need an object data source when dynamically binding to the gridview.

DataTableBindingMarkup

To bind the DataTable you will have to write a big of code:

  1.        protected void Page_Load(object sender, EventArgs e)
  2.         {
  3.             if (!IsPostBack)
  4.             {
  5.                 gvEmployees.DataSource = GetListOfEmployees();
  6.                 gvEmployees.DataBind();
  7.             }
  8.         }
  9.  
  10.         protected DataTable GetListOfEmployees()
  11.         {
  12.             DataTable table = new DataTable();
  13.             SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["EmpConnection"].ConnectionString);
  14.             SqlCommand command = new SqlCommand("GetEmployees", conn);
  15.             command.CommandType = System.Data.CommandType.StoredProcedure;
  16.             command.Connection.Open();
  17.             using(SqlDataReader reader = command.ExecuteReader())
  18.             {
  19.                 table.Load(reader);
  20.             }
  21.  
  22.             return table;
  23.         }

The key to dynamic binding is that you will have to rebind the data on any postback manually. Depending on what you are doing this may more difficult than not. In this example, I have filled a DataTable from a SQLDataReader which reads the results from a Stored Procedure. However, as mentioned the DataTable itself could arrive from anywhere in your system for binding. If you have a DataTable that differs from the output you want to show you will have to manually add the columns to the markup on the gridview and set the “AutoGenerateColumns” property to false (it is default set to true).

The Good:

  • Very flexible to just about anything…
  • You can easily adjust data source rows and even columns and have the presentation layer update without touching it
  • Allows for dynamic data
  • Allows for altering of data source from a database to anything without adjusting your presentation layer
  • Provides great control over the Architecture of your project
  • Uses SqlDataReader which provides great performance between your application and database server

The Bad:

  • Data is dynamically binded, requiring you to handle everything, including: postbacks, paging, sorting, etc
  • Additional up front work is required to begin binding to your GridView with data

The Scoop: Dynamic Binding with DataTables provides a massive degree of flexibility, however also requires a great degree of custom code and work around any additional features. Your project may require dynamic columns, or use DataTables, in which case you may have no choice but to use DataTables. This may be your main que to start binding with DataTables.

Method 3: XSD (Visual Studio DataSets)

The XSD (or Visual Studio DataSets) are very much a different beast (if I may say so). The XSD originated in Visual Studio 2005, so its a relatively new piece of the Framework. It essentially allows you to create DataTables and DataSet components in a visual way. You simply walk through its Wizard designing like you would a Database. You can create a DataSet just like any other item:

AddingDataSet

After you’ve created you DataSet1.xsd, all you have to do is right click anywhere in the gray and select “Add Table Adapter”:

AddingTableAdapter

Once you follow the wizard through your matching TableAdapter should look similar to above. Much like a DataTable you will see the fields and types that belong to that adapter, and also available methods that were created for retrieving that data.  Depending on your selections in the Wizard you will have generated components for a complete “Fill” dataset that allows for updating, inserting, deleting, and viewing:

AddingTableAdapter2

The Wizard will even allow you to configure Optimistic Concurrency on the adapter (checks that the data its changing is newest before making changes).

Once you have your DataSet and TableAdapters created you can then bind your ObjectDataSource as a Object to this TableAdapter which will show up in your IntelliSense list. Here is the markup:

DataSetMarkup

Thats it you are done now. This method also requires writing zero code. Additionally, you could also write a Bussiness Object layer in this example, that would serve the ObjectDataSource and read from the TableAdapter programmatically. I will hopefully blog about this process in the future and provide some examples. Until then here are some examples of that method:

http://quickstarts.asp.net/QuickStartv20/aspnet/doc/ctrlref/data/objectdatasource.aspx

The Good:

  • Zero code required
  • Once again, it is very fast development time due to its stream lined capability.
  • Provides additional level of scalability of the project since it has a DataAccess/BussinessLogic Layer of sorts
  • Allows you to visually edit and alter your results for a project
  • Paging and Sorting once again out of the box and ready to go (with the same caveats previously mentioned).
  • Full CRUD support – which really streamlines things
  • Provides reuseable CRUD functionality across multiple pages.

The Bad:

  • XSD requires a ton of XML and schema’s that are written behind the scenes.  Although in most cases your dev is streamlined, XSD’s can cause a lot of problematic unknown errors if the XML meta data gets mixed up…
  • You could burn a lot of time dealing with the XSD’isms
  • Uses full DataSet filling, meaning performance is quite slow
  • Programmatically not that easy to manipulate and use
  • Less degree of flexibility in business logic.

The Scoop: Again, XSD’s provide streamlined development process. However, you may pay the price later because of the low flexibility of business logic incorporated in the XSD. This is a great intermediate solution or step up if the Direct Binding method doesn’t quite meet your criteria.

Method 4: Custom Objects, IEnumerable, and DataReaders

There is still something to be said for writing your own custom code for a project without using XSD or datasets. By using some custom objects you get maximum flexibility as well as strongly typed objects with the greatest performance. In using custom objects, most people don’t even know that they can bind a List or Collection object  (or anything that inherits from IEnumerable interface) to a GridView, or repeater, etc. In fact you even get some nice intelliSense on the markup page in Visual Studio 2008 when referring to the object. Here is a quick rundown on how to implement it:

First off, we will need a custom object. In my example I have a simple employee class:

  1.    public class Employee
  2.     {
  3.         public int ID { get; set; }
  4.         public string First { get; set; }
  5.         public string Last { get; set; }
  6.     } 

The markup:

CustomBindingMarkup

Of course you don’t have to specify the specific columns if you set “AutoGenerateColumns” to true. However, I wanted you to see how you can refer to an object in the template section (for your custom implementations). Next take a look at how you can bind the objects:

  1.        protected void Page_Load(object sender, EventArgs e)
  2.         {
  3.             if (!IsPostBack)
  4.             {
  5.                 gvEmployees.DataSource = GetListOfEmployees();
  6.                 gvEmployees.DataBind();
  7.             }
  8.         }
  9.  
  10.         protected List GetListOfEmployees()
  11.         {
  12.             List emps = new List();
  13.  
  14.             SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["EmpConnection"].ConnectionString);
  15.             SqlCommand command = new SqlCommand("GetEmployees", conn);
  16.             command.CommandType = System.Data.CommandType.StoredProcedure;
  17.             command.Connection.Open();
  18.             using (SqlDataReader reader = command.ExecuteReader())
  19.             {
  20.                 while (reader.Read())
  21.                 {
  22.                     Employee emp = new Employee();
  23.                     emp.ID = reader.GetInt32(reader.GetOrdinal("ID"));
  24.                     emp.First = reader.GetString(reader.GetOrdinal("FirstName"));
  25.                     emp.Last = reader.GetString(reader.GetOrdinal("LastName"));
  26.                     emps.Add(emp);
  27.                 }
  28.             }
  29.             command.Connection.Close();
  30.             command.Connection.Dispose();
  31.  
  32.             return emps;
  33.         }
  34.     }

Pretty simple eh? Yet effective!!! This is my favourite since it allows you implement this functionality on any system while still maintaining ultimate control over your custom object and data model structure. It still has the caveats mentioned with binding a DataTable since it is still dynamic binding of the object.

The Good:

  • Awesome flexibility since you can use your own custom objects and properties
  • Excellent integration into any existing system using custom objects to drive their data model
  • Strongly typed method, including IntelliSense at all levels including the markup
  • Very fast and performant since it uses a SqlDataReader

The Bad:

  • Requires additional time on a new project to develop your model and data access layer architecture
  • Requires custom sorting and paging to be implemented in required
  • Slow development time in comparison to other methods
  • Implementing CRUD functionality takes additional work since custom objects have to be hydrated on their way back to the database.

The Scoop: The custom methodology really really rocks in my opinion when you need performance, since it give you complete control over all area’s of the project with next to no overhead from any of the components that you would get on a DataTable, and especially on a XSD. However, when dealing with a CRUD situation, it can be quite tedious and monotonous to have to write additional code for something that you can get out of the box using another method.

Conclusions…

What to say to sum it all up? In the end, each of these methods provides their own advantages and disadvantges. It should be your requirements, scalability, and project type that dictates which one of these methods to use.

Keep in mind that you can always use a combination of these methods. Perhaps, using an ObjectDataSource class that implements a custom data access layer is the way to go. Once you understand the tools at each level and how to piece your presentation to your bussiness logic / data access together while still maintaining that level of separation your best choice of architecture for binding will be quite apparant.

Download Source Example Files  / Solution

Leave a Reply