Wednesday, May 26, 2010

A Silverlight RSS Reader

A Silverlight RSS Reader

This article shows how to create a simple RSS Reader in silverlight.We can start creating a silverlight application from the Visual studio templates and it'll automatically create a silverlight project and a Web application into which silverlight is hosted.We need to fetch data from the feed url that a user is entered and for that purpose, we are going to use a WCF service so that the silverlight client can make asynchronous calls and can fetch the response.So Lets start by adding a WCF service to the Web application, here in my sample its RSSReaderService.svc.If we add WCF service directly to the Web application instead of creating a new service project, then the service will be hosted in the web application itself when we start the application. I  created a ServiceContract IRSSReaderService and added an OperationContract GetFeed(string uri), a method which defines an operation for the service contract.

namespace RSSReader.Web
{
  [ServiceContract]
  public interface IRSSReaderService
  {
    [OperationContract]
    IEnumerable<RSSItem> GetFeed(string uri);
  }
}

We need to implement the operation contract GetFeed(string uri) in our service code behind which is implementing IRSSReaderService.We are using  System.ServiceModel.Syndication, a namespace using for Syndication object model, for loading the syndication feed from the XmlReader instantiated with the specified feed url. For sending the properties from the feed to the client we created a DataContract RSSItem with DataMembers like Title,Summary,PublishDate and Permalink. We can customize the data members according to our requirement but here i am simply using these much information to send to the client.

[DataContract]
public class RSSItem
{
  [DataMember]
  public string Title { get; set; }

After creating this DataContract we create an XmlReader with the specified url and load the SyndicationFeed items from this XMLReader. Now we can use LINQ for iterating through this syndication items and for fetching the required information from those items.We are populating the RSSItem that we created and sending an IEnumerable of this object from the service to the client.So our GetFeed(string url) method implementation looks like,

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RSSReaderService : IRSSReaderService
{

  public IEnumerable<RSSItem> GetFeed(string uri)
  {
    XmlReader reader = XmlReader.Create(uri);
    SyndicationFeed rssFeed = SyndicationFeed.Load(reader);

    var items = from p in rssFeed.Items
                select new RSSItem
                {
                   Title = p.Title.Text,
                   Summary = p.Summary.Text.Trim(),
                   Permalink = (p.Links.FirstOrDefault() != null) ? p.Links.FirstOrDefault().GetAbsoluteUri() : null,
                   PublishDate = p.PublishDate.LocalDateTime.ToString("dd/MMM/yyyy")
                };
    return items;
  }

}

So our service is completed and ready for consumption by the client.Now we need to create the silverlight client.Add service reference to the Silverlight project and then create a user control in the silverlight project, in the sample you can see the user control UC_RSSReader.xaml. I added some controls like ListBox in this usercontrol, templated and added binding for those controls.We edited the ItemTemplate for the ListBox and added custom data template which consist of TextBlocks and ListBox to display the feed data as required.We can customize this as per our requirement or as per the amount of data to be displayed.Now we are having the usercontrol that is binded to the corresponding properties. ListBox is displaying the feed data from the URL and the XAML looks like,

<ListBox x:Name="RSSFeed"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Grid.Row="2"
Grid.ColumnSpan="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid MinWidth="{Binding ElementName=LayoutRoot, Path=ActualWidth}"
MaxWidth="{Binding ElementName=LayoutRoot, Path=ActualWidth}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Title}"
FontFamily="Verdana"
FontSize="13" />
<TextBlock Grid.Row="2"
Text="{Binding PublishDate}"
HorizontalAlignment="Left"
FontFamily="Verdana"
FontSize="11" />
<HyperlinkButton Grid.Row="2"
Content="Read Article>>"
NavigateUri="{Binding Permalink}"
HorizontalAlignment="Center"
FontFamily="Verdana"
FontSize="11"
FontStyle="Italic"
ToolTipService.ToolTip="{Binding Title}"
TargetName="__blank" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

I am not using MVVM for this application as this is a very basic sample.Event subscribtion is straight forward and we have all the logic in the code behind itself.While clicking the fetch Button we are sending the request to the service with the feed url entered, fetching the data from the service and binding that result with ListBox. ListBox will display the Title, PublishDate and also a permalink to the original feed item.


private void FetchRSS_Click(object sender, RoutedEventArgs e)
{
  if (!string.IsNullOrEmpty(RSSFeedUrlTextBox.Text.Trim()) 
     && Uri.IsWellFormedUriString(RSSFeedUrlTextBox.Text.Trim(), UriKind.Absolute))
  {
    LoadingTextBlock.Visibility = Visibility.Visible;
    RSSFeed.Items.Clear();
    RSSReaderServiceClient RSSReaderServiceClient = new RSSReaderServiceClient();
    RSSReaderServiceClient.GetFeedCompleted += new EventHandler<GetFeedCompletedEventArgs>(RSSReaderServiceClient_GetFeedCompleted);
    RSSReaderServiceClient.GetFeedAsync((new Uri(RSSFeedUrlTextBox.Text)).ToString());                
  }
}

void RSSReaderServiceClient_GetFeedCompleted(object sender, GetFeedCompletedEventArgs e)
{
  RSSFeed.ItemsSource = e.Result;
  LoadingTextBlock.Visibility = Visibility.Collapsed;
}

Add this usercontrol to the main page and compile it.Before running the application don't forget to put the cross domain policy file in the web application root.Otherwise silverlight client can't communicate with the WCF service.If you get any run time errors for the sample application then delete and add the service reference again in the silverlight project.

0 comments:

Post a Comment