1

At the moment, I am generating xml and json data using the following code:

public class App
{
    public string app_name;
    public string app_path;

    public App(string m_app_name, string m_app_path)
    {
        app_name = m_app_name;
        app_path = m_app_path;
    }

    public App() { }
}

[ScriptService]
public class Apps : WebService {
    List<App> App = new List<App>();

    SqlConnection connection;
    SqlCommand command;
    SqlDataReader reader;

    [WebMethod()]
    public List<App> GetUserApps()
    {
        var apps = new List<App>();

        using (connection = new SqlConnection(ConfigurationManager.AppSettings["connString"]))
        {


                using (command = new SqlCommand(@"some query here", connection))
                {
                    connection.Open();
                    using (reader = command.ExecuteReader())
                    {
                        int AppNameIndex = reader.GetOrdinal("application_name");
                        int AppPathIndex = reader.GetOrdinal("application_path");

                        while (reader.Read())
                        {
                            apps.Add(new App(reader.GetString(AppNameIndex), reader.GetString(AppPathIndex)));
                        }
                    }
                }



        }

        return apps;
    }
}

If I then request this in javascript using application/json; charset=utf-8, I automatically get json data.

My problem is that I need to get data from an external RSS feed, instead of a local database, and convert that to json data so I can call it the same way using javascript.

Anyone know how I can capture the RSS feed http://www.hotukdeals.com/rss/hot using similar code as above?

oshirowanen
  • 15,297
  • 82
  • 198
  • 350
  • 1
    So I guess you need to 1. read in your RSS feed 2. convert the RSS structure to the JSON structure you want 3. put this code into a web service 4. set it up to either cache the result or cache the RSS data read. It doesn't sound particularly difficult - which part of this are you stuck on? Alternatively if you're happier serving data from a database then you could always write a job to fetch your RSS data and add it to your database, so you can then serve that out. That would also allow you to control the number of records in your JSON feed. – Rup Jul 09 '12 at 10:04
  • Shouldn't the convert from rss to json happen automatically, similar to how I am converting the sql to json in the above code automatically? Basically, I want to use the same concept in the above code, but change from getting the data from a database and use an rss feed instead. – oshirowanen Jul 09 '12 at 10:07
  • 2
    That code isn't converting from SQL automatically, it's converting from your list of `App` structures that you've read from your database. Read your RSS data into similar structures and it will output JSON automatically, yes - but you still need to read the data in yourself. – Rup Jul 09 '12 at 10:09
  • In that case, I guess I just need help with getting rid of the sql part and sticking in an rss reader, the rest should be automatic? – oshirowanen Jul 09 '12 at 11:34
  • Yes, you're right, I'm extending my answer to show how to do it using my parser - though you're welcome to try and use the built-in one instead if you prefer – Graham Wager Jul 09 '12 at 14:31

2 Answers2

6

Add a refrence to System.ServiceModel.Web and use the following code:

    [WebMethod()]     
    public List<Deal> GetDeals()
    {
        var deals = new List<Deal>();

        XmlReader xr = XmlReader.Create("http://www.hotukdeals.com/rss/hot");
        SyndicationFeed feed = SyndicationFeed.Load(xr);

        foreach (var item in feed.Items)
        {
            deals.Add(new Deal { Title = item.Title.Text, Summary = item.Summary.Text });
        }

        return deals;
    }

Replace the Deal class above with whatever class you need for your app and add some error handling as well :)

Check the SyndicationFeed documentation for details.


To read a dc:date property, add

using System.Xml.Linq;

and then add this in the foreach loop ( converts the first date )

        var dates = item.ElementExtensions.Where(x => x.OuterName == "date");

        if(dates.Count() > 0) 
        {
            var element = dates.First().GetObject<XElement>();
            var d = DateTime.Parse(element.Value);
        }

I found it in this article: Reading non-standard elements in a SyndicationItem with SyndicationFeed

Community
  • 1
  • 1
Tommy Grovnes
  • 4,126
  • 2
  • 25
  • 40
  • I've added `Using System.ServiceModel.Web;` at the top, but I'm not getting XmlReader as an option via Visual Studio's Intellisense. If I then ignore it and use similar code to your code, I get an error `The type or namespace name 'XmlReader' could not be found (are you missing a using directive or an assembly reference?)` – oshirowanen Jul 10 '12 at 08:38
  • 1
    XmlReader should be in [System.Xml](http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.aspx) and SyndicationFeed in [System.ServiceModel.Syndication](http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationfeed.aspx); you'll need to add references to System.Xml and System.ServiceModel (for .NET 4; System.ServiceModel.Web for .NET 3.5) respectively. By references I mean right-click on the References folder in your project - you'll need the `using` s too but you need the assembly references first. – Rup Jul 10 '12 at 08:42
  • It almost seems to be working. `item.Title.Text` works, but I have another element in another feed which is `Link`. So when I try `item.Link.Text`, I get an error message: `CS1061: 'System.ServiceModel.Syndication.SyndicationItem' does not contain a definition for 'Link' and no extension method 'Link' accepting a first argument of type 'System.ServiceModel.Syndication.SyndicationItem' could be found (are you missing a using directive or an assembly reference?)` – oshirowanen Jul 10 '12 at 09:05
  • 1
    Both the feed and the item have a Links collection which you can access f.ex. item.Links[0].Uri for the first link of the item (there can be 0 to many) same for feed.Links – Tommy Grovnes Jul 10 '12 at 09:19
  • That worked, Thanks! The last thing, how do I access the the items published date? – oshirowanen Jul 10 '12 at 09:33
  • I tried using `item.PublishDate.ToString()`, but it always seems to return `01/01/0001 00:00:00 +00:00` when the published date in the feed looks something like `2012-07-09T13:05:22+00:00`. – oshirowanen Jul 10 '12 at 09:45
  • 1
    That's not the standard date field. You'll probably have to dig that one out of the [`item.ElementExtensions` property](http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationitem.elementextensions(v=vs.90)). – Rup Jul 10 '12 at 09:50
  • ... oh and you probably want to cache either the web service output or the RSS you read to avoid making a new request for the RSS for every request to the web service too. – Rup Jul 10 '12 at 10:23
  • 1
    This works add using System.Xml.Linq; and then add this in the foreach loop (it will fail if dc:date is missing so add error handling) XElement element = item.ElementExtensions.Where(x => x.OuterName == "date").FirstOrDefault().GetObject(); Console.WriteLine(element.Value); // holds the date Found it it this article http://stackoverflow.com/q/319591/1045728 – Tommy Grovnes Jul 10 '12 at 11:07
0

A web feed is a data format used for providing users with frequently updated content. Suppose you are designing the home page of any website and you want to show feeds from some popular or useful website. In this case the following example might be helpful.

In this example the feeds consumed are shown in a listview. But you can use any control and show the feeds accordingly.

The script for listview is:

<div>
    <asp:ListView ID="FeedList" runat="server" 
            onitemdatabound="FeedList_ItemDataBound" DataKeyNames="Title,Link" >
        <LayoutTemplate > 
           <div runat="server" id="ItemPlaceHolder">
           </div>
        </LayoutTemplate>
        <ItemTemplate>
            <asp:Label ID="title" runat="server"></asp:Label>
            <br />
            <asp:HyperLink ID="link" runat="server"></asp:HyperLink>
            <br />
        </ItemTemplate>
    </asp:ListView>
</div>

The code behind file for the example is:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Data;
using System.ServiceModel.Syndication; // used for feed implementation

public partial class FeedConsume : System.Web.UI.Page
{
    /// <summary>
    /// databind function of listview is called from this function.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void Page_Load(object sender, EventArgs e)
    {
        // See if feed data is in the cache
        IEnumerable<SyndicationItem> items = Cache["Feeds"] as IEnumerable<SyndicationItem>;
        if (items == null)
        {
            // If not present in cache then get it from sender's website
            try
            {
                SyndicationFeed sfFeed = SyndicationFeed.Load(XmlReader.Create("FEED URL OF senders website"));

                // every website has a static url which contains their feed and we can get the feed from that url. 
                items = sfFeed.Items;
                }
            catch
            {
                items = new List<SyndicationItem>();
            }
            // Add the items to the cache
            Cache.Insert("Feeds", items, null, DateTime.Now.AddHours(1.0),TimeSpan.Zero);
        }

        // Creating the datatable to bind it to the listview. This datatable will contain all the feeds from the senders website.
        DataTable dtItems = new DataTable();
        dtItems.Columns.Add("Title", typeof(string));
        dtItems.Columns.Add("Link", typeof(string));
        foreach (SyndicationItem synItem in items)
        {
            dtItems.Rows.Add(synItem.Title.Text, synItem.Links[0].Uri.ToString());
        }
        FeedList.DataSource = dtItems;
        FeedList.DataBind(); 
    }

    /// <summary>
    /// Controls in listView are assigned proper value
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void FeedList_ItemDataBound(object sender, ListViewItemEventArgs e)
    {
        ListViewDataItem lvDataItem = (ListViewDataItem)e.Item;
        DataRowView drvItem = (DataRowView)lvDataItem.DataItem;
        Label title = (Label)e.Item.FindControl("title");
        title.Text = drvItem["Title"].ToString();
        HyperLink link = (HyperLink)e.Item.FindControl("link");
        link.Text = drvItem["Link"].ToString();
        link.NavigateUrl = drvItem["Link"].ToString();
    }
}

Note: We should always care for data we get from other websites.

Rup
  • 33,765
  • 9
  • 83
  • 112
Narendra
  • 3,069
  • 7
  • 30
  • 51