BASICS: ObjectDataSource Control


By Peter Bromberg
Printer Friendly Version
  

ObjectDataSource is a new hybrid control for ASP.NET 2.0 This article shows an unusual use of the control to retrieve and display RSS Feed search results from the web, instead of getting data from a database.



I must confess I am a bit jealous of many of the n00b developers who've just started out using Visual Studio 2005 since it appeared late last year. They got started with a whole new set of controls, many of which can be "hooked up" to do incredibly productive things -- with no code at all. Meanwhile, we .NET "Old Timers", having become used to doing things "our way", have passed up on all this goodness in favor of the familiar. How many noob developers know that the DataGrid in ASP.NET 2.0 is still there? Yep. It's just not on the Toolbox by default. But, hey -- they've got the much better GridView, so what do they care?

At any rate, there is a set of controls that newer developers seem to have gravitated to, leaving the older developers like moi in the lurch - and that is the DataSource controls. One of those, the ObjectDataSource control, I find quite interesting.

ObjectDataSource is a member of the family of ASP.NET data source controls that enable declarative databinding against underlying data stores. Most data source controls are designed for a two-tiered application architecture, where the page interacts directly with the data provider. Many ASP.NET developers want to encapsulate data retrieval, often combined with business logic, into a tier component object that introduces an additional layer between the presentation page and data provider. ObjectDataSource allows developers to structure applications using this three-tiered architecture and still take advantage of the benefits of declarative databinding in ASP.NET. It's not a full-fledged Object Relational Mapping infrastructure, but it is a step in the right direction, with familiar semantics that make it highly useful. Old-timers will probably remember "ObjectSpaces" and how it went through several iterations and finally was killed off (quite unceremoniously, I believe).

The ObjectDataSource control object model is similar to the SqlDataSource control, but instead of a ConnectionString property, ObjectDataSource exposes a TypeName property that specifies a type to instantiate for performing the data operations. Like the command properties of SqlDataSource, the ObjectDataSource control supports properties such as SelectMethod, UpdateMethod, InsertMethod, and DeleteMethod for specifying methods of the associated type to call to perform these data operations. The difference is that instead of being SqlCommands (SelectCommand, for example) the methods are actual methods of the class that was specified for the ObjectDataSource control to use. This gives you, the developer, the opportunity to do a lot more business logic coding in your type, while still offering the familiar page-facing databinding interface that GridView, DataList and their brethren can consume happily. ObjectDataSource performs all this magic through reflection- hence it is wise to create a target class that has static methods in order to avoid constant and repetitive instantiation and collection every time  a method is used.

The advantages of this approach haven't been lost on .NET Developers -- many code generators are now producing code for Data layers that is ObjectDataSource - compliant. One example that I like is the "SubSonic Zero Code DAL" (formerly called "ActionPack"). I started out creating a SQLite Provider for it, but I had to stop because their code is still a moving target. Once it settles down, I'll resume my work.

I first became interested in the ObjectDataSource control when I visited Peter Kellner's code for the MembershipProvider. Peter has done a bang-up job of integrating this into an ASP.NET "Membership Management" page - a version of which I featured in a previous article here.

So let's take a look at some sample code that utilizes the ObjectDataSource. I'll keep this example simple in keeping with the "BASICS" theme of these articles. What I'm going to do is illustrate the flexibility of the ObjectDataSource by not having it get data from a database at all. Instead, our type will go out to the web and retrieve search result feeds from Live.com feed search in RSS format. These will then be databound to a GridView on the page. I'll also put in a "search" textbox and the required code and declarative markup to enable the control to use the search term that the user enters as a "select parameter" in the same way one would add a search term to the "WHERE CLAUSE" of a SQL statement.

First, lets have a look at the two classes I use to handle the "data access"- the RSSFeed class, and the RSSDataSource class:

RSS Feed Class:

using System;

using System.Collections.Generic;

using System.Text;

 

namespace RSSObjectDataSource

{

    public class RSSFeed

    {

        private string _title;

        public string Title

        {

            get { return _title; }

            set { _title = value; }

        }

 

        private string _description;

        public string Description

        {

            get { return _description; }

            set { _description = value; }

        }

 

        private string _link;

        public string Link

        {

            get { return _link; }

            set { _link = value; }

        }

 

        private DateTime _pubDate;

        public DateTime PubDate

        {

            get { return _pubDate; }

            set { _pubDate = value; }

        }

 

        public RSSFeed(string title, string description, string link, DateTime pubDate)

        {

            this._title = title;

            this._description = description;

            this._link = link;

            this._pubDate = pubDate;  

        }

    }

}


The RSSFeed class, as can be seen above, is just a simplified "container" for an RSS Feed Item, and it only contains the most important fields (title, description, link, and pubDate).

The RSS DataSource class:

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

using System.Data;

 

namespace RSSObjectDataSource

{

    public static class RSSDataSource

    {

        public static List<RSSFeed> FeedList = new List<RSSFeed>();

        public static string LastSearchTerm = "";

        private static string url1 = "http://search.live.com/feeds/results.aspx?q=";

        private static string url2 = "&mkt=en-US&format=rss&count=50"; // sorry they don't go over "50".

 

        public static int GetCount( string searchTerm)

        {

            return FeedList.Count;

        }

 

        public static ICollection<RSSFeed> GetFeeds( string searchTerm)

        {

            LastSearchTerm = searchTerm;

            DataSet ds = new DataSet();

            if (searchTerm == "") searchTerm = "a";

            ds.ReadXml(string.Concat(url1, searchTerm, url2));

            DataTable dt = ds.Tables[2];

            List<RSSFeed> list= new List<RSSFeed>();

            foreach (DataRow row in dt.Rows)

            {

                string title = (string)row["title"];

                string description =(string)row["description"];

                string link = (string)row["link"];

                DateTime pubDate =DateTime.Now;

                // handle malformed RFC822 date formats

                try{

                    pubDate =Convert.ToDateTime(row["pubDate"]);

                   }

                catch {}

                   list.Add(new RSSFeed(title, description, link, pubDate));

            }

            FeedList = list;

            return list;   

        }

        public static ICollection<RSSFeed> GetFeeds(string searchTerm,
                             int
maxRows, int startRowIndex)

        {         

            DataSet ds = new DataSet();

            if (searchTerm == "") searchTerm = "a";

            ds.ReadXml(string.Concat(url1, searchTerm, url2));

            DataTable dt = ds.Tables[2];

            List<RSSFeed> list = new List<RSSFeed>();         

            foreach (DataRow row in dt.Rows)

            {

                string title = (string)row["title"];

                string description = (string)row["description"];

                string link = (string)row["link"];

                DateTime pubDate = DateTime.Now;

                try

                {

                    pubDate = Convert.ToDateTime(row["pubDate"]);

                }

                catch { }

                list.Add(new RSSFeed(title, description, link, pubDate));

            }

            FeedList = list;

            if (list.Count < maxRows) maxRows = list.Count;

            List<RSSFeed> retList = new List<RSSFeed>();

            for (int i=startRowIndex;i<maxRows;i++)

            {

                retList.Add(list[i]);

            }

            return retList;

        }

    }

}

RSSDataSource provides the "guts" of the mechanism, and exposes methods that are designed specifically for the ObjectDataSource control to be able to consume.

Now let's take a look at some declarative markup on the page that pulls this all together:

<form id="form1" runat="server">
    <div>
      <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Search" /></div>
        <asp:GridView ID="_rssGrid" runat="server" AllowPaging="True" AutoGenerateColumns="False"
            DataSourceID="_rssObjectDataSource" DataKeyNames="pubDate" 
                      CellPadding="4" ForeColor="#333333" GridLines="None" Width="802px"                          PageSize="50" RowHeaderColumn="pubDate" ShowFooter="True"> <Columns> <asp:HyperLinkField DataNavigateUrlFields="link" DataTextField="title" Text="Title" /> <asp:BoundField HeaderText="pubDate" DataField="pubDate" SortExpression="pubDate" /> <asp:BoundField DataField="description" HeaderText="description" SortExpression="description" /> </Columns> <FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" /> <RowStyle BackColor="#FFFBD6" ForeColor="#333333" /> <SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" /> <PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center"                      BorderStyle="Solid" BorderWidth="1px" /> <HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="White" /> <AlternatingRowStyle BackColor="White" /> </asp:GridView> <asp:ObjectDataSource ID="_rssObjectDataSource" runat="server" SelectMethod="GetFeeds" TypeName="RSSObjectDataSource.RSSDataSource" CacheDuration ="21600" EnablePaging="True" MaximumRowsParameterName="maxRows" SelectCountMethod="GetCount" OnSelecting="_rssObjectDataSource_Selecting"> <SelectParameters> <asp:ControlParameter ControlID="TextBox1" DefaultValue="a"                         Name="searchTerm" PropertyName="Text" Type="String" /> </SelectParameters> </asp:ObjectDataSource> </form>

The GridView here specifies the pubDate as the DataKey ("Identity" field), a hyperlink field for the title and link, and bound fields for the pubDate and description items.

The ObjectDataSource specifies "GetFeeds" as it's select method, the TypeName of my RSSDataSource class, a Cache Duration of 21600 (6 hours - caching is built in),

and a SelectParameter of the TextBox for the search term. The interesting thing about all this is that if you look at the codebehind class for this page, there is NO CODE! It all works automatically based on the settings of the control.

Here is an example display (reduced size) where the user has typed "ASP.NET" into the search textbox. This is a nice way to see search results that point directly to RSS Feeds, and when you click on a link that you like, you can subscribe to the feed immediately in IE 7 or Firefox 2.0:

ObjectDataSource is a unique control that has lots of potential for easing the acquisition of and display of data from a variety of sources.

Download the Visual Studio 2005 Web Application Project



Biography
Peter Bromberg is a C# MVP, MCP, and .NET expert who has worked in banking ,financial and telephony for 20 years. Pete focuses exclusively on the .NET Platform, and his samples at GotDotNet.com have been downloaded over 56,000 times. Peter enjoys producing 3D raytraced digital photo collage with Maya, the beach, and fine wines. You can view Peter's UnBlog and IttyUrl sites.
Please post questions at forums, not via email!

button
 
Article Discussion: BASICS: ObjectDataSource Control
Peter Bromberg posted at 08-Nov-06 07:26
Original Article

 
paging is not working
madhu gandra replied to Peter Bromberg at 12-Dec-06 05:25

I have downloaded the code and tested. It's working but paging links are not working. When I clikcked the page number link blank page with just text box and button is shown. Can you please show how to fix ths issue?


 
Why Is RssDataSource Static?
Greg Lusk replied to Peter Bromberg at 13-Aug-08 10:38

Peter,

I'm curious why the RSSDataSource class is static. If you have two instances of your control on a page, wouldn't you get the exact same feed list for both controls? Would it be valid to make the RSSDataSource a class that could be instantiated?


 
sure you can.
Peter Bromberg replied to Greg Lusk at 13-Aug-08 01:35
I wasn't thinking about that when I wrote up the sample.

 
Thanks
Greg Lusk replied to Peter Bromberg at 13-Aug-08 01:44

Peter,

Thanks for the response. The reason I asked is that we were running into a problem where our object instances were getting rebuilt by the ObjectDataSource every time that it binds data. We're developing a control that speaks in real time in the browser using SAPI, and we didn't realize that it doesn't use the same instance every time. So we were losing object references in our control code. Our business object didn't use static methods, so we thought we might need to implement it differently.