Magnus Baneryd
Jan 18, 2010
  712
(0 votes)

Yet another Feed Reader gadget, but with a twist

     
  1. Are you tired of writing all your HTML views in regular ASP.NET?
  2. Are you tired of having to write strange Html like <$If(…){%> Hola <%}%> syntax?
  3. Or do you just want to learn something new?

Then this post might be something for you.

This post will guide you through how to switch the standard ASP.NET Mvc view engine and use the Spark View Engine instead. The idea with Spark is to allow html to dominate the flow and the code to fit seamlessly into it.

Ok, this is how you do it.

Download the latest Spark View Engine; extract the files and copy Spark.dll and Spark.Web.Mvc.dll to the Public Templates bin folder.

Open the Public Templates project and add both assemblies to project references, you also need to add System.Web.Mvc and System.ServiceModel.Web.

Add two new folders to the project root: Controllers and Views.

Add a new controller to the Controllers folder, call it SparkyController.cs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.ServiceModel.Syndication;
using System.Web.Mvc;
using System.Xml;
using EPiServer.Shell.Gadgets;
 
namespace EPiServer.Shell.Controllers
{
    [Gadget(Title="Yet another Feed Reader")]
    public class SparkyController : Controller
    {
        /// <summary>
        /// Returns a <see cref="Feed"/> object to the view
        /// </summary>
        /// <returns><see cref="Feed"/> object</returns>
        public ActionResult Index()
        {
            return View(GetFeed(new Uri("http://feeds.wired.com/wired/index"), 10));
        }
 
        /// <summary>
        /// Returns a <see cref="Feed"/> object
        /// </summary>
        /// <param name="feedUrl">Url to fetch the feed from</param>
        /// <param name="maxCount">Maxmium number of items to fetch</param>
        /// <returns>a Feed object</returns>
        private Feed GetFeed(Uri feedUrl, int maxCount)
        {
            //Sanity check the feed url. The XmlTextReader happily accepts local files so make sure it's a remote http(s):// url we're loading.
            if (!feedUrl.Scheme.StartsWith("http", StringComparison.OrdinalIgnoreCase))
            {
                throw new UriFormatException("Invalid feed Url: " + feedUrl.ToString());
            }
 
            // Try to load the feed into a feed formatter
            WebRequest webRequest = WebRequest.Create(feedUrl);
            webRequest.Timeout = 5000;
            using (var response = webRequest.GetResponse())
            using (XmlReader reader = new XmlTextReader(response.GetResponseStream()))
            {
                // Try the Url as an RSS feed
                SyndicationFeedFormatter feedFormatter = new Rss20FeedFormatter();
                if (!feedFormatter.CanRead(reader))
                {
                    // No, then try reading as an atom feed
                    feedFormatter = new Atom10FeedFormatter();
                }
                if (!feedFormatter.CanRead(reader))
                {
                    throw new ArgumentException("The url given does not contain a valid RSS or Atom feed: " + feedUrl.ToString());
                }
                feedFormatter.ReadFrom(reader);
                var feed = new Feed()
                {
                    Title = feedFormatter.Feed.Title.Text,
                    Items = feedFormatter.Feed.Items.OrderBy(i => i.PublishDate).Take(maxCount)
                };
                return feed;
            }
        }
    }
 
    /// <summary>
    /// View model for a RSS/Atom feed
    /// </summary>
    public class Feed
    {
        /// <summary>
        /// Feed title
        /// </summary>
        public string Title { get; set; }
 
        /// <summary>
        /// Feed Items
        /// </summary>
        public IEnumerable<SyndicationItem> Items { get; set; }
    }
}
Now we have to create a view for the controller, inside the View folder create another folder called Sparky and add a file in that folder with the name Index.spark.

image

 

Index.spark

<!-- We need linq -->
<use namespace="System.Linq" />
<use namespace="System.Web" />
<!-- Map the model object as a Feed so we can use it like this: ViewData.Model.Title etc -->
<viewdata model="EPiServer.Shell.Controllers.Feed"/>
 
<!--NOT BEST PRACTICE-->
<style>
  ul.rssItemList{
    list-style-image: none;
    list-style-position: inside;
    list-style-type: square;
    color: #AAAAAA;
  }
 
  .feedReader li{
    color: Black
  }
 
  .feedReader small{
    font-size: 0.8em;
    color: #AAAAAA;
  }
</style>
 
<script type="text/javascript">
   1: //<![CDATA[
   2:  
   3:   //THIS IS NOT BEST PRACTICE
   4:   $(document).ready(function(e){
   5:     //Widgitize the tooltips
   6:     $(".feedReader .epi-toolTip").epiToolTip();
   7:   });
   8: //]]>
</script>
 
 
<div class="epi-padding feedReader">
  <h3>${Html.Encode(ViewData.Model.Title)}</h3>
 
   <!--If we have any items in the feed start by writing an UL element-->
  <ul if="ViewData.Model.Items.Any()" class="rssItemList">
    <!-- Foreach feed item in the View model create a LI element -->
    <li each="var item in ViewData.Model.Items">
      <a href="${item.Links[0].Uri}">${Html.Encode(HttpUtility.HtmlDecode(item.Title.Text))} <small>- ${item.PublishDate.DateTime.ToShortDateString()}</small></a>
      <!--Create a tooltip div, will be widgetized by the javascript-->
      <div class='epi-toolTip'>${item.Summary.Text}</div>
    </li>
  </ul>
</div>

If we dig a little deeper inside the code you will see that we map the model to the Feed class returned by the Sparky controller, this is equal to

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Feed>" %>

that you would write in a regular Asp.NET MVC view. We do this because we want to have a strongly typed model in the view.

Let’s tie it together

Ok, now we have created the view and the controller and the project should compile. However the gadget will not appear in the gadget list and the web server won’t recognize the .spark as a Spark view. So we need to do a couple of more things before everything works.

First we need EPiServer.Shell to recognize Public Templates as  Shell Module. Open web.config and scroll down to <episerver.shell>  and add/update the publicModules list to include the Public Templates.

<publicModules rootPath="~/public" autoDiscovery="Minimal">
      <add name="Public" resourcePath="~/">
        <assemblies>
          <add assembly="EPiServer.Templates.Public" />
        </assemblies>
      </add>
</publicModules>

Then we have to register the Spark View Engine so that MVC will recognize the .spark as a spark view.

Open Global.asax.cs and add the Spark View Engine to Application_Start.

protected void Application_Start(Object sender, EventArgs e)
{
    XFormControl.ControlSetup += new EventHandler(XForm_ControlSetup);
    //Register the Spark view engine
    ViewEngines.Engines.Insert(0, new SparkViewFactory());
}

Now it should be possible to add the “Yet Another Feed Reader” gadget to the dashboard and read the latest Wired top stories.

 

Questions?

Jan 18, 2010

Comments

Please login to comment.
Latest blogs
Preview multiple Visitor Groups directly while browsing your Optimizely site

Visitor groups are great - it's an easy way to add personalization towards market segments to your site. But it does come with it's own set of...

Allan Thraen | Sep 26, 2022 | Syndicated blog

The Report Center is finally back in Optimizely CMS 12

With Episerver.CMS.UI 12.12.0 the Report Center is finally re-introduced in the core product.

Tomas Hensrud Gulla | Sep 26, 2022 | Syndicated blog

Dynamic Route in ASP.NET Core When MapDynamicControllerRoute Does Not Work

Background Creating one of the add-on for Optimizely I had to deal with challenge to register dynamically route for the API controller. Dynamic rou...

valdis | Sep 25, 2022 | Syndicated blog

404 Error on Static Assets Within an Optimizely plugin

Background With the move to CMS 12 and .NET 5/6, developers are now able to build Plugins and Extensions using Razor Class Libraries (RCL).  These...

Mark Stott | Sep 23, 2022

How to bypass the content creation view in Optimizely

Something that has come up a couple of times in the last few year is feedback from content editors about the editing view that comes up when creati...

Ynze | Sep 23, 2022 | Syndicated blog

Welcome to Optimizely World's New Tech Video Portal

Optimizely, leader in the digital experience realm, has become a wealth of world class SaaS products including Web Experimentation, Full Stack, B2B...

The Developer Marketing Team of Optimizely | Sep 22, 2022