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?

Published Thursday, April 26, 2007 11:00 AM by Eilon
Filed under: , ,

Comments

# re: Using ObjectDataSource to do the dirty work for your custom data source

Friday, April 27, 2007 6:18 AM by Mark Wisecarver

The .NET 2.0 ObjectDataSource is, um, sweet.

I used it with Ajax to upgrade an ASP 3 set of records from SQL Server 2005 and they not only load faster, much faster, for the client but are also easier to browse via a dropdown control. . .stunning indeed.

# re: Using ObjectDataSource to do the dirty work for your custom data source

Friday, April 27, 2007 5:59 PM by Richard

Or why not use a ORM tool such as LLBLGen or NHibernate that generates the DataSourceControl for you and you can go home at lunch?!?!? ;)

# re: Using ObjectDataSource to do the dirty work for your custom data source

Sunday, April 29, 2007 9:20 PM by Ryan Smallegan

I second Richard's comment. I use .netTiers to do the same thing :-)

# re: Using ObjectDataSource to do the dirty work for your custom data source

Monday, June 11, 2007 10:27 AM by Godot
Unfortunately for me, coming from VB6 to VB.NET, it is very difficult to convert this to VB. I tried an online converter, but it had numerous syntactical challenges it couldn't overcome and I am not facile enough with the language/framework to correct the problems. Do you have a VB.NET version of this code?

# re: Using ObjectDataSource to do the dirty work for your custom data source

Monday, July 16, 2007 3:15 PM by Rowan Jugernauth

Hello there, Eilon.

I'm not new at C#, but lately I've taken to working with data by using DataSources, Adapters and everything else. After a few days of development, a question hit me - what's the purpose of an ObjectDataSource if you've already created your table adapters and business objects which provide the logic behind fetching data?

Rowan

# re: Using ObjectDataSource to do the dirty work for your custom data source

Monday, July 16, 2007 4:26 PM by Eilon

Hi Rowan,

The idea behind the ObjectDataSource is that, as you've discovered, it doesn't do any data access at all. It never connects to a database and it never updates any rows. The reason we have ObjectDataSource is to enable declarative databinding between data bound controls (for example, GridView, FormView, and DetailsView) and your business object. Without ObjectDataSource you'd have to handle a variety of events on the page and on the data bound control to ensure you hook them up correctly and pass the data around.

Thanks,

Eilon

# re: Using ObjectDataSource to do the dirty work for your custom data source

Wednesday, August 1, 2007 5:42 AM by kutti

i have fetching the particular data's from data grid to textboxes.Here fetching the data's should be using checkboxes.

# re: Using ObjectDataSource to do the dirty work for your custom data source

Thursday, April 17, 2008 3:08 AM by Ken Miller

I'm convinced the objectdatasource doesn't work like it's supposed to, but I'm having difficulty finding a workaround for the update method.  Still stuck at "Could not find a property named '' on the type specified by the dataobjecttypename property.

# re: Using ObjectDataSource to do the dirty work for your custom data source

Thursday, April 17, 2008 12:51 PM by Eilon

Hi Ken,

What property can't it find? The ObjectDataSource requires a public get/set property that matches the name of the field you're trying to update. For example, if the field name is CustomerName and the data object is of type MyCustomer, you need to have:

public class MyCustomer {

   public string CustomerName { get; set; }

}

Thanks,

Eilon

# re: Using ObjectDataSource to do the dirty work for your custom data source

Thursday, April 17, 2008 3:43 PM by Ken Miller

I'm approaching this through vb.net; I haven't formally declared the objectdatasource through code.  I thought the idea was that I configured the typed dataset, and wired it through the objectdatasource.  

I've enabled paging on the objectdatasource and that's all working with select method, but when I attempt an update, I get the message referred to above ("could not find the property named [first column in control] on the type specified...

Here's my Objectdatasource ASP.NET code.

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" EnablePaging="true" TypeName="DataSetLookupTableAdapters.LookupTableAdapter" ConvertNullToDBNull="True" DataObjectTypeName="DataSetLookup" SelectMethod="GetData" UpdateMethod="spLookupValueUpdate" MaximumRowsParameterName="maxrows" StartRowIndexParameterName="startrow" SelectCountMethod="spLookupValuesCount">

            <UpdateParameters>

                <asp:ControlParameter ControlID="GridView1" Name="@ID" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@Ltype" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@LItem" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@Value" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@Ordinal" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@A" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@R" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@S" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@Text" PropertyName="SelectedValue" />

                <asp:ControlParameter ControlID="GridView1" Name="@Submenuitem" PropertyName="SelectedValue" />

            </UpdateParameters>

        </asp:ObjectDataSource>

Do I really have to write a property for every parameter?  Your comment indicates I'm missing a property on the objectdatasource.  However, the error message specifies that the location where the property cannot be found is in the typed dataset.

I'd like to find some example code showing it all put together.

Thanks...

# re: Using ObjectDataSource to do the dirty work for your custom data source

Wednesday, August 20, 2008 6:46 PM by fairbanj

The problem I am having is the way that ObjectDataSource is when passing in a DataSet.  The selection works great, but the update requires a method on the object that has all the parameters in the updated row... why not just return a DataRow?  This makes it impossible for me to use a generic object over different tables.  I even tried to use the params keyword to allow a variable parameter list and it still barfs.  Very frustrating.  

# re: Using ObjectDataSource to do the dirty work for your custom data source

Monday, September 29, 2008 5:48 AM by Nik

hi,

I'm having trouble getting this code to work. I've copied the code at the top of the page verbatim but when run i get the following error:

Parser Error Message: Unknown server tag 'eStuff:FoodDataSource'.

Source Error:

Line 10:     <form id="form1" runat="server">

Line 11:         <div>

Line 12:             <eStuff:FoodDataSource runat="server" ID="FoodData" FoodType="ice cream">

Line 13:             </eStuff:FoodDataSource>

Line 14:             <asp:GridView ID="FoodGrid" DataSourceID="FoodData" runat="server">

Can someone please let me know if there is an erro with the original code or is there soomething the code reqwuires that I'm not aware of?

# re: Using ObjectDataSource to do the dirty work for your custom data source

Monday, September 29, 2008 2:07 PM by Eilon

Nik - You need to include a tag mapping either in web.config (msdn.microsoft.com/.../ms164641.aspx) or in a <%@ Register %> directive in the page. If you look closely it's shown in the code sample:

<%@ Register Namespace="eStuff.Samples" TagPrefix="eStuff" %>

Thanks,

Eilon

# re: Using ObjectDataSource to do the dirty work for your custom data source

Friday, October 31, 2008 11:58 AM by Darren

I'm getting the same error

Unknown server tag 'eStuff:FoodDataSource'.

but I do have

<%@ Register Namespace="eStuff.Samples" TagPrefix="eStuff" %>

at the top of my page.

# re: Using ObjectDataSource to do the dirty work for your custom data source

Monday, December 14, 2009 9:32 AM by BM

Same as the last two guys, unknown server tag 'eStuff:FoodDataSource' when I try to debug the aspx page ...