Using ObjectDataSource to do the dirty work for your custom data source
Since ASP.NET 2.0 was released in 2005 many of you have taken advantage of the new data source control controls. Drop a GridView on the page. Bind it to a data source. Check a few checkboxes. Run the page. Go home early!
However, some of you want to take data sources a step further. I've recently been chatting with Tobias Hertkorn on his blog about Trying to enhance ObjectDataSource. I figured I'd take advantage of Windows Live Writer to make a nice looking blog post about some neat techniques you can use to enhance the ObjectDataSource control. Tobi is trying to derive from ObjectDataSource to add some new and much simplified functionality for his users.
Sure enough, Tobi encountered problems taking advantage of ObjectDataSource to do the dirty work of data source architecture. My response mostly boiled down to "this type of extensibility was not what we had in mind for ObjectDataSource" and "We felt that if you need this degree of customization that writing your own data source is not that much of a stretch."
While I'm not taking back those statements, there are still a lot of neat things you can do with ObjectDataSource. For example, let's say you want to have a friendly data source that lets you choose from some simple sources of data instead of requiring users to select a type name and a select method. Following is the all new eStuff Sample FoodDataSource. The FoodDataSource has just one required property: FoodType. You pick the FoodType, and the FoodDataSource figures out what data to return. Pretty simple, isn't it?
namespace eStuff.Samples { using System.Collections; using System.Web.UI; using System.Web.UI.WebControls; public class FoodDataSource : ObjectDataSource { private string _foodType; public FoodDataSource() : base(typeof(FoodData).FullName, "GetFood") { // Constructor parameters: // - ObjectDataSource complains if we don't have a TypeName set. // - Our custom object's SelectMethod is always called GetFood. // Hook up the ObjectCreating event so we can use our custom object ObjectCreating += delegate(object sender, ObjectDataSourceEventArgs e) { // Here we create our custom object that the ObjectDataSource will use e.ObjectInstance = new FoodData(this); }; } // Public property for the user to choose their food type public string FoodType { get { return _foodType; } set { _foodType = value; } } // Custom data object that returns yummy foods private sealed class FoodData { private FoodDataSource _dataSource; public FoodData(FoodDataSource dataSource) { _dataSource = dataSource; } public IEnumerable GetFood() { string foodType = _dataSource.FoodType; yield return foodType + " yummy 1"; yield return foodType + " yummy 2"; yield return foodType + " yummy 3"; yield return foodType + " yummy 4"; } } } }
And now a sample ASPX page that uses the data source:
<%@ Page Language="C#" %> <%@ Register Namespace="eStuff.Samples" TagPrefix="eStuff" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Yummy Foods</title> </head> <body> <form id="form1" runat="server"> <div> <eStuff:FoodDataSource runat="server" ID="FoodData" FoodType="ice cream"> </eStuff:FoodDataSource> <asp:GridView ID="FoodGrid" DataSourceID="FoodData" runat="server"> </asp:GridView> </div> </form> </body> </html>
As you can tell from the page, using the FoodDataSource is indeed very simple. No need to worry about long type names and select methods! All the real work was even done in ObjectDataSource's constructor. By passing a reference to the FoodDataSource into the FoodData object, the FoodData object can lazily decide what data it wants to return from its SelectMethod ("GetFood"). My initial version of this control was quite hacky about how and when it knew what data to return. But I ended up with this rather clean approach that doesn't violate and philosophical or technical rules about writing controls.
Have any of you adapted the ObjectDataSource to do your dirty work? Did you run into any problems?