Using MVC and jQuery to build a NewsTicker

Scott Guthrie tweeted a link to an article by Scott Mitchell. In it Scott wrote a handy news ticker in Asp.Net . And he wrote it in VB. I recommend going to read it before doing anything else.

It is a handy little example and a very good demonstration of jQuery in action. I actually first thought of using it in The Feedreader. Of course if I wanted to do that I’d have to re-write it as an MVC application rather than an ASP.Net website.

This is a nice academic exercise on moving from ASP.Met to MVC.

So lets get cracking.

Groundwork

So. We begin by creating an empty MVC2 project.

Actually, we began when we read Scott article. Its important to understand what Scotts trying toacomplish and how Scotts code works, before we shamelessly copy it.

The first thing you are going to want to do is make sure that Scotts’ ticker.js and jquery-1.4.4.min.js are in your MVC Scripts folder and included in the project. Also, you’ll want to copy Scott’s css files across. I put them in a folder called Styles and made sure it was included in the project.

Now, we need a Masterpage before we can create any Views. So add one in Views/Shared. We are shamelessly copying Scotts example in every detail. So go ahead and copy the markup in Scotts example and paste it into the your masterpage. You’ll want to change the script and css paths accordingly.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
<script type="text/javascript" src="../../Scripts/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="../../Scripts/ticker.js"></script>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
<link href="../../Styles/sinorcaish-screen.css" rel="stylesheet" type="text/css" />
<link href="../../Styles/CustomStyles.css" rel="stylesheet" type="text/css" />
<link href="../../Styles/NewsTicker.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<!-- ======== Header ======== -->
<div id="header">
<div class="left">
News Ticker Demo
</div>
<div class="right">
<%=DateTime.Now.ToShortDateString()%>
</div>
<div class="subheader">
<em>News me!</em>
</div>
</div>

<!-- ======== Left Sidebar ======== -->
<div id="sidebar">
<div>
<ul>
<li><%: Html.ActionLink("Simple Ticker Demo", "Simple","Home")%></li>
<li><%: Html.ActionLink("Dynamic Ticker Demo", "Dynamic","Home")%></li>
</ul>
</div>
</div>

<!-- ======== Main Content ======== -->
<div id="main">
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">

</asp:ContentPlaceHolder>
</div>

<!-- ======== Footer ======== -->

<div id="footer">
ASP.NET application designed by <a href="http://www.4guysfromrolla.com/ScottMitchell.shtml">Scott Mitchell</a>.
Website design by <a href="mailto:J.Zaitseff@zap.org.au">John Zaitseff</a>, and available
at <a href="http://www.opendesigns.org/preview/?template=1700">OpenDesigns.org</a>.
</div>

</form>
</body>
</html>

Remember to change the links in the sidebar to ActionLinks.

Controllers

The next thing we need to do is to write a Controller. Typically the first controller in any MVC application is the home controller.

So go ahead and create one, adding three ActionResult methods: Index, Simple and Dynamic.

public class HomeController : Controller
{
//
// GET: /Home/

public ActionResult Index()
{
return View();
}
public ActionResult Simple()
{
return View();
}
public ActionResult Dynamic()
{
return View();
}
}

At this point, create a View for Index and copy the HTML from Default.aspx and stick it in the content control thats been created in the view.
Then, add an empty view for the Simple controller. Since this is straightforward HTML, we simply copy the contents of both ContentPlaceHolders in Simple.aspx into the two that have been created for us in the view

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

<h2>Simple News Ticker Demo</h2>
<p>
This demo shows two simple news tickers. Each news ticker has the same hard-coded news items. The
first one shows only the body of each news item, one at a time; the second one shows the headline,
body, and published date of each news item and shows three at a time.
</p>

<h3>One Row News Ticker</h3>
<div class="ticker stretched">
<ul id="latestNews1">
<li>
<div class="body">Politician Joe Smith has assembled a news conference for this afternoon to apologize for some
indiscretion he had. This is Mr. Smith's third such "apology press conference" this year.</div>
</li>
<li>
<div class="body">Did you know that you can play the fun (and addictive!) board game
Axis &amp; Allies online? Head on over to <a target="_blank" href="http://gamesbyemail.com/Games/WW2">http://gamesbyemail.com/Games/WW2</a>
and give it a whirl!</div>
</li>
<li>
<div class="body">A recent study by some doctors somewhere showed a strong correlation between unhealthy eating
and unheathly people. More studies are to be performed to verify these findings.</div>
</li>
<li>
<div class="body">This just in - ASP.NET is awesome! jQuery is not so bad, either. In fact, most technologies are pretty darn
cool. For more information, see <a href="http://www.4guysfromrolla.com/" target="_blank">4GuysFromRolla.com</a>.</div>
</li>
<li>
<div class="body">Last night the local sports team won a convincing victory over their hated rivals. After the game there was much
jubilation.</div>
</li>
<li>
<div class="body">Visit my blog. Please. You can find it at <a href="http://scottonwriting.net/sowblog/">ScottOnWriting.NET</a>.</div>
</li>
</ul>
</div>

<h3>Three Rows News Ticker</h3>
<div class="ticker threeRows medium">
<ul id="latestNews3">
<li>
<div class="header">Politician schedules news conference</div>
<div class="body">Politician Joe Smith has assembled a news conference for this afternoon to apologize for some
indiscretion he had. This is Mr. Smith's third such "apology press conference" this year.</div>
<div class="footer">Published @ 8:30 AM</div>
</li>
<li>
<div class="header">Play Axis &amp; Allies Online!</div>
<div class="body">Did you know that you can play the fun (and addictive!) board game
Axis &amp; Allies online? Head on over to <a target="_blank" href="http://gamesbyemail.com/Games/WW2">http://gamesbyemail.com/Games/WW2</a>
and give it a whirl!</div>
<div class="footer">Published @ 8:38 AM</div>
</li>
<li>
<div class="header">Study links unhealthy food to unhealthy people</div>
<div class="body">A recent study by some doctors somewhere showed a strong correlation between unhealthy eating
and unheathy people. More studies are to be performed to verify these findings.</div>
<div class="footer">Published @ 9:00 AM</div>
</li>
<li>
<div class="header">ASP.NET is awesome!</div>
<div class="body">This just in - ASP.NET is awesome! jQuery is not so bad, either. In fact, most technologies are pretty darn
cool. For more information, see <a href="http://www.4guysfromrolla.com/" target="_blank">4GuysFromRolla.com</a>.</div>
<div class="footer">Published @ 9:09 AM</div>
</li>
<li>
<div class="header">Local sports team wins</div>
<div class="body">Last night the local sports team won a convincing victory over their hated rivals. After the game there was much
jubilation.</div>
<div class="footer">Published @ 9:35 AM</div>
</li>
<li>
<div class="header">Read my blog</div>
<div class="body">Please. You can find it at <a href="http://scottonwriting.net/sowblog/">ScottOnWriting.NET</a>.</div>
<div class="footer">Published @ 10:30 AM</div>
</li>
</ul>
</div>

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
$(document).ready(function () {
startTicker('#latestNews1', 1, 5000);
startTicker('#latestNews3', 3, 5000);
});
</script>
</asp:Content>

Note the javascript in the “head” ContentPlaceHolder. This fires as soon as the page as finished rendering. Scott has more details about it in his article.

Model

Now, this is the hard part.

Scott Mitchells’ example used an ASP ListView control. If you’re writing ASP.Net code a listview is the easiest way to accomplish what we’re trying to do.  You’ll notice as well that Scott passes the contents of SyndicationFeed.Items directly to the databound control. Now there is most probably a way of using Scott’s code directly in an MVC view. However, for the purposes of convenience we’ll dispense with the ListView and iterate over items ourselves.

There is also the issue of the Formatting of the items. You’ll notice that the ItemTemplate in Scotts’ code calls FormatSummary and FormatPubDate from the HTML. Because of the separation between code and HTML in MVC we can’t do that.

The solution to both of these “problems” is to do things ourselves. The M in MVC stands for model. So we need a model before we go any further. The two pieces of data we need are contained in the Summary and the PublishDate fields of the SyndicationItems. So this is what our model looks like:

public class Model
{
public String Title { get; set; }
public string Date { get; set; }
}

FormatSummary and Format PubDate, obviously need to be part of  the HomeController class:

public static string FormatSummary(string summary){
string header = "ScottOnWriting: ";

//Remove the leading "ScottOnWriting: "
if (summary.StartsWith(header)){
return summary.Substring(header.Length);
}
return summary;
}

public static string FormatPubDate(DateTimeOffset pubDate)
{
return pubDate.ToString("h:mm, MMM d");
}

View

Now that the groundwork has been laid, we can write our actual HTML view.  First we need to add our javascript function:

<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
$(document).ready(function () {
startTicker('#tweets', 2, 4500);
});
</script>
</asp:Content>

This javascript function will do nothing unless ticker.js exists in your scripts folder. It will end up in the page header and will be executed as soon as the document has finished rendering. Also note that we are passing 2 in here. We could pass in any number we wanted. Scott explains more about this in his article.

Now, the fact is that the original implementation using a ListView basically iterated over all the objects in the datasource and output a select piece of HTML for each item in that collection. So, we’ll do the same.

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

<h2>Dynamic News Ticker Demo</h2>
<p>
This demo shows a ticker whose contents are populated dynamically. This particular example pulls the most recent tweets from
<a href="http://twitter.com/ScottOnWriting">my Twitter account</a> and displays them in a ticker, showing two entries at a time.
</p>
<h3>@ScottOnWriting's Latest Tweets</h3>
<div class="ticker twoRows medium">
<ul id="tweets">
<%foreach (var item in this.Model)
{  %>
<li>
<div class="header" style="font-weight: normal">
<%= item.Title.ToString()%>
</div>
<div class="footer">Tweeted @ <%: item.Date.ToString()%></div>
</li>
<%} %>
</ul>
</div>
</asp:Content>

Note the careful placement of our Foreach  statement. Our list item (<li/>) and the HTML with in it will be repeated on each pass over the loop body. Also, note how we are using var item in this.Model. Our View knows exactly what datatype has been passed to it. In fact, our view is actually View<Model.Model>. Yes, its a generic. And we are using var here to avoid typing Model.Model over and over again.

 

So, in a nutshell, the above code does the exact same thing as a ListView Control.

Hit run and it should be working.

Note to self– Use OutputCache in MVC 3

I’m just reading ScottGu’s post on the MVC 3 release candidate.

What got me really thinking was the output cache attribute:

image

Scott explains:

Notice how the DailySpecials method above has an [OutputCache] attribute on it.  This indicates that the partial content rendered by it should be cached (for 3600 seconds/1 hour).  We are also indicating that the cached content should automatically vary based on the category parameter.

If we have 10 categories of products, our DailySpecials method will end up caching 10 different lists of specials – and the appropriate specials list (computers or diapers) will be output depending upon what product category the user is browsing in.  Importantly: no database access or processing logic will happen if the partial content is served out of the output cache – which will reduce the load on our server and speed up the response time.

This new mechanism provides a pretty clean and easy way to add partial-page output caching to your applications.

So, with my Windows Azure Feedreader in mind,  my note to self is as follows:

In a couple of weeks, when we get to the shared items Rss feed, we can use this code. We vary by user id rather than by category in the example above.

I’m actually quite relived, as I was wondering how we’d do the shared items Rss feed. These actions would, arguably, be highly trafficked and reading directly from the blobs (which was my original plan) would be too bandwidth intensive. Problem solved.

I’m very excited about MVC 3 as a whole, but when i see the direct application of features, I get even more excited.

In fact, when Razor first came out, I really was going to use it for the Feedreader instead.

Windows Azure Feedreader Episode 7: User Subscriptions

Episode 7 is up. I somehow found time to do it over several days.

There are some audio issues, but they are minor. There is some humming noises for most of the show. I’ve yet to figure out where they came from. Apologies for that.

 

This week we

  • clear up our HTML Views
  • implement user subscriptions

We aren’t finished with user subscriptions by any means. We need to modify our OPML handling code to take account of the logged in user.

 

Enjoy:

Remember, you can head over to vimeo.com to see the show in all its HD glory.

Next week we’ll finished up that user subscriptions  code in the OPML handling code. 

And we’ll start our update code as well.

Windows Azure Feedreader: Choosing a Login System – Which would you choose?

Update: Here’s the related screencast episode.

As you may have noticed in the last episode (episode4), writing the Feed Reader has got to the stage where we require UserID’s.

Given the delicate nature of login credentials and the security precautions required, its much easier to hand off the details to Google Federated Login, or even Windows Live ID. These services simply give us a return token indicating who has logged in.

The previous version of the feed reader used Windows Live ID. Its a very simple implementation. It consists of a single MVC controller, and a small iFrame containing the login button. It’s elegantly simple. Since its MVC, there are no issue running it on Windows Azure. The reason why I picked it the last time, was a) its simplicity and b) its part of the Windows Azure ecosystem.

The alternative is to use Google Federated Login. This is a combination of OpenID and OAuth. The implementation is certainly much more involved, with a lot of back and forth with Google’s Servers.

OpenIdDiagram[1]

 

  1. The web application asks the end user to log in by offering a set of log-in options, including using their Google account.
  2. The user selects the “Sign in with Google” option. See Designing a Login User Interface for more options.
  3. The web application sends a “discovery” request to Google to get information on the Google login authentication endpoint.
  4. Google returns an XRDS document, which contains the endpoint address.
  5. The web application sends a login authentication request to the Google endpoint address.
  6. This action redirects the user to a Google Federated Login page, either in the same browser window or in a popup window, and the user is asked to sign in.
  7. Once logged in, Google displays a confirmation page (redirect version / popup version) and notifies the user that a third-party application is requesting authentication. The page asks the user to confirm or reject linking their Google account login with the web application login. If the web application is using OpenID+OAuth, the user is then asked to approve access to a specified set of Google services. Both the login and user information sharing must be approved by the user for authentication to continue. The user does not have the option of approving one but not the other.Note: If the user is already logged into their Google account, or has previously approved automatic login for this web application, the login step or the approval step (or both) may be skipped.
  8. If the user approves the authentication, Google returns the user to the URL specified in the openid.return_to parameter of the original request. A Google-supplied identifier, which has no relationship to the user’s actual Google account name or password, is appended as the query parameter openid.claimed_id. If the request also included attribute exchange, additional user information may be appended. For OpenID+OAuth, an authorized OAuth request token is also returned.
  9. The web application uses the Google-supplied identifier to recognize the user and allow access to application features and data. For OpenID+OAuth, the web application uses the request token to continue the OAuth sequence and gain access to the user’s Google services.Note: OpenID authentication for Google Apps (hosted) accounts requires an additional discovery step. See OpenID API for Google Apps accounts.

 

As you can see, an involved process.

There is a C# library available called  dontnetopenauth, and I’ll be investigating the integration of this into MVC and its use in the Feed Reader.

There is one advantage of using Google Accounts, and that’s the fact that  the Google Base Data API lets us import Google Reader Subscriptions.

It may well be possible to allow the use of dual login systems. Certainly, sites like stackoverflow.com use this to great effect.

Why is choosing an external login system important?

Well, firstly its one less username and password combination that has to be remembered.

Secondly, security considerations are onus of the authentication provider.

If we were to go with multiple authentication providers, I’d add a third reason: Not having an account with the chosen authentication provider is a source of frustration for users.

So, the question is, dear readers, which option would you choose?

  1. Google Federated login
  2. Windows Live ID
  3. Both

Windows Azure Feed Reader Episode 3

Sorry for the lateness of this posting. Real life keeps getting in the way.

This weeks episode is a bit of a departure from the previous two episodes. The original recording I did on Friday had absolutely no sound. So, instead of re-doing everything. I give you a deep walkthrough of the code. Be as that may, I did condense an hours worth of coding into a 20 minute segment – which is probably a good thing.

As I mentioned last week, this week we get our code to actually do stuff – like downloading, parsing and displaying a feed in the MVCFrontEnd.

We get some housekeeping done as well – I re-wrote the OPML reader using LINQ and Extension Methods. We’ll test this next week.

The final 20 minutes, or so is a fine demonstration of voodoo troubleshooting ( i.e. Hit run and see what breaks) but we get Scott Hanselmans feed parsed and displayed. The View needs a bit of touching up to display the feed better, but be as that may, it works.

Since we get a lot done this week, its rather longer – 1 hour and 9 minutes. I could probably edit out all the pregnant pauses. 🙂

Here’s the show:

Success! My 2nd HD attempt uploaded last night. Click here to see the HD on vimeo.com. Enjoy.

Remember, the code lives at http://windowsazurefeeds.codeplex.com

Warning: Contains Programmer Humor. Handle with care.

Rob Conery has a hilarious post up entitled: Restraining Order Granted for Microsoft’s C-Sharp Compiler

A taster:

A judge from Microsoft’s .NET County submitted a 00110101 year restraining order on Friday against Microsoft’s C-Sharp development community. The stay-away order bans Microsoft developers from using the compiler’s services as a development tool, forcing them to find other means to support their claims they "they are done" with features they are developing.

Highly recommended that you read the rest of it.

Thanks for the laugh Rob.

Windows Azure Feed Reader, Episode 2

A few days late (meant to have this up on Tuesday). Sorry. But here is part 2 of my Series on building a Feed Reader for the windows Azure platform.

If you remember, last week we covered the basics and we ended  by saying that this week’s episode would be working with Windows Azure proper.

Well this week we cover the following:

  • Webroles (continued)
  • CloudQueueClient
  • CloudQueue
  • CloudBlobClient
  • CloudBlobContainer
  • CloudBlob
  • Windows Azure tables
  • LINQ (no PLINQ yet)
  • Lambdas (the very basics)
  • Extension Methods

Now, I did do some unplanned stuff this week. I abstracted away all the storage logic into its own worker class. I originally planned to have this in Fetchfeed itself. This actually makes more sense than my original plan.

I’ve added Name services classes for Containers and Queues as well, just so each class lives in its own file.

Like last weeks, this episode is warts and all. I’m slowly getting the hang of this screencasting thing, so I’ll be getting better as time goes on I’m sure. Its forcing me to think things through a little more thoroughly as well.

Enjoy:

Next week we’ll start looking at the MVC project and hopefully get it to display a few feeds for us. We might even try get the OPML reader up to scratch as well.

PS. This weeks show is higher res than the last time. let me know if its better.