BASICS: ObjectDataSource Control

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

By Peter Bromberg   Popularity  (11648 Views)