When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, April 21, 2004

Creating a Content Rater

By Scott Mitchell


Introduction


The content rater at MSDN. If you ever read an article on Microsoft's MSDN Web site, such as my article An Extensive Examination of User Controls, you'll notice that at the bottom of the article there's an interface for the reader to rate the content. (See the screenshot to the right.) Specifically, the user can rate the quality of the article on a scale from 1 to 9, with 1 being Poor, and 9 being Outstanding. In addition to affixing a numerical rating of the article, the reader can also provide optional comments in a textbox. Also included is a graph showing how other readers have rated the article. (CoDe Magazine's Web site uses a similar content rating system.)

- continued -

The other day I thought it would be neat to add such functionality to my blog, ScottOnWriting.NET. Namely, I wanted to allow users to rate each blog entry, so that I could get a better idea of what content my visitors found most compelling. Another benefit of allowing users to rank content, is that after sufficient data has been collected you can provide users with a list of "most popular" content items. In this article I will walk you through the steps I took to create the content rater used on my blog. You are more than welcome to take my code and apply it to your ASP.NET Web site, or to extend it as needed.

First Things First: The Data Model


Each time a user rates a content item, the rating - along with any comments - are stored in a database (specifically, a Microsoft SQL Server 2000 database). I opted to store the ratings and comments in a database (as opposed to an XML file, for example), for one main reason: extracting metrics on the data is a cinch when using SQL. For example, a simple, single SQL query can be used to quickly determine the average rating for a particular content item. A more involved query could be used to determine what authors wrote the highest rated content, or what days of the week the least popular items were published.

To store the ratings for my blog's entries, I created a single table, blog_Ratings, where each row in this table would correspond to one rating from a user. The blog_Ratings table has the following structure:

Field NameDatatype
RatingIDint, PK, IDENTITY
Ratingtinyint
Commentsnvarchar(3000)
ContentIDint, FK
DateAddeddatetime

The Rating field contains the numeric rating the user assigned to the content item, while Comments stores the comments provided (if any). ContentID is a foreign key that relates the rating back to a particular content item. (For my blog I use the .Text blog engine, which stores each blog entry as a row in a table called blog_Content. This foreign-key ties a rating to the particular blog entry being rated.) Finally, the DateAdded field specifies the date/time the rating was made (with a default value of getdate()).

Creating the User Interface


With the data model complete, my next step was to create the user interface for rating a content item. Rather than display a ranking of 1 to 9 like MSDN does, I decided to simplify my design and only allow for a rating from 1 to 5 instead. I started by creating a new User Control in my ASP.NET Web application, and crafted a nearly identical interface to MSDN's content rater. The screenshot below shows my User Control in Visual Studio .NET and in action on my blog (you can download the User Control at the end of this article).

The User Control in Visual Studio .NET

 

The content rater, when viewed through a browser.

The User Control is contained within an HTML <table>, dividing the interface into two halves: a left half, which displays the rating interface; and a right-half, which displays the average rating and a graph depicting the rating history. The left-half contains two Panel Web controls. The first Panel, pnlCastVote, contains the HTML markup and Web controls for rating a content item. The second Panel, pnlVoteCast, contains just a message thanking the user for rating the content. If a particular user has not rated a particular content item, they are shown the pnlCastVote Panel. If, however, they have already rated the content item, they are shown the pnlVoteCast Panel. (Cookies are used to remember what content items the user has rated.)

Specifying the Content Being Rated and Collecting the User's Rating


The User Control code-behind class contains a ContentID property that indicates the ID of the content being rated. That is, to use the content rater in an ASP.NET Web page, you'd include the User Control and then in the ASP.NET Web page's code-behind class you'd set the User Control's ContentID property to current content item's ID value. It is essential that this property be set in the ASP.NET Web page (such as in the Page_Load event handler), because the User Control must know what content item it is rating.

To rate a content item, the user selects one of the radio buttons and clicks the Rate Content button. This causes a postback and runs an event handler wired up to the Rate Content button's Click event. The event handler code checks to determine what radio button was selected, marks the user as having voted for the content item, and then calls the blog_AddRating stored procedure, passing in the user's rating, comments, and the ID for the content being rated. (The blog_AddRating stored procedure simply does an INSERT into blog_Ratings.)

Remembering If a User Has Rated a Content Item


Since we don't want one user to be able to rate a single content item dozens of times, after a user has rated a content item they are shown a message thanking them for their rating, as opposed to seeing the rating interface. For further protection, a cookie is used to record what content items the user has rated. If the user comes to a content item they've already rated, rather than seeing the rating interface, they are shown a message thanking them for their rating.

Cookies are by no means a fail-safe method to ensure that each visitor only rates a content item once. For one thing, users can configure their browsers to not accept cookies. Also, a cookie is specific to a Web browser, so a single person could use different browsers, or different computers, and record their rating more than once. The point is, the content rater I created by no means guarantees the validity of the ratings. If you want to be certain that there is only one rating per user, then you'd need to have a database of user accounts, and tie a rating to a particular user.

For the content rater I created, I created a Boolean HasVoted property in the User Control code-behind class that can be used to determine if a user has already voted on a particular content item or not. The property's get accessor checks to see if a cookie is in place, indicating that the user has rated this content item. The set accessor adds the appropriate cookie. The code for the HasVoted property is shown below:

public bool HasVoted
{
   get
   {
      // Return true if the cookie DOESN'T EXIST, false if it does
      return (Request.Cookies["sowBlog"] != null && 
              Request.Cookies["sowBlog"][String.Concat("ContentID-", 
                                                 ContentID)] != null);
   }
   set
   {
      // Create the cookie
      if (Request.Cookies["sowBlog"] == null)
         Response.Cookies.Add(new HttpCookie("sowBlog"));

      Response.Cookies["sowBlog"][String.Concat("ContentID-", 
                                                 ContentID)] = "true";
      Response.Cookies["sowBlog"].Expires = DateTime.Now.AddYears(1);
   }
}

Note that the HasVoted property checks a cookie called sowBlog's value titled ContentID-ID, where ID is the ID of the content item specified by the ASP.NET Web page containing this User Control. (This property helps illustrate the importance of having the ASP.NET Web page specify the User Control's ContentID property; the ContentID specifies what cookie value to search for.)

Wrapping Up: Showing the Voting Statistics


The final piece of the puzzle is having the right-half of the rating interface display the total number of people who have rated the content, along with a graph showing the vote breakdown. This is accomplished in the DisplayRateScreen() method in the User Control, and is called from the User Control's Page_Load event handler. DisplayRateScreen() calls the blog_GetRatingInfo stored procedure to get the information on how many votes for each rating there were, along with the average rating and how many total ratings have been made. This stored procedure expects a ContentID input parameter, specifying the content item for which to generate the stats, and has the following syntax:

CREATE PROCEDURE blog_GetRatingInfo
(
   @ContentID int
) AS

If Exists(SELECT 1 FROM blog_Ratings WHERE ContentID = @ContentID)
   SELECT
       SUM(CASE WHEN Rating = 1 THEN 1 ELSE 0 END) As Rating1Count,
       SUM(CASE WHEN Rating = 2 THEN 1 ELSE 0 END) As Rating2Count,
       SUM(CASE WHEN Rating = 3 THEN 1 ELSE 0 END) As Rating3Count,
       SUM(CASE WHEN Rating = 4 THEN 1 ELSE 0 END) As Rating4Count,
       SUM(CASE WHEN Rating = 5 THEN 1 ELSE 0 END) As Rating5Count,
       AVG(CONVERT(float, Rating)) As AvgRating,
       COUNT(1) As RatingCount
   FROM
       blog_Ratings
   WHERE
       ContentID = @ContentID
   GROUP BY
       ContentID
Else
   SELECT
     0 As Rating1Count,
     0 As Rating2Count,
     0 As Rating3Count,
     0 As Rating4Count,
     0 As Rating5Count,
     0.0 As AvgRating,
     0 As RatingCount

(The above stored procedure was provided by Richard Deeming...)

As you can see, the stored procedure returns one row with seven columns. The columns Rating1Count through Rating5Count return the number of 1 through 5 ratings the content item received. AvgRating returns the average rating, while RatingCount returns the total number of ratings recorded for this content item.

The graph depicting the rating breakdown is generated with an HTML <table>, which one column for each of the five possible ratings. Each column in the graph contains a single image, (bcImage.gif), which is stretched to a height proportional to the number of ratings received. For example, if there are twice as many 5 ratings for a content item than there are 4 ratings, the 5 rating column height will be twice that of the 4 column height. The specific proportion is computed as the number of votes for that rating, divided by the maximum number of votes for any rating, multiplied by 50 (to scale the maximum height to 50 pixels).

Learn About Adding Additional Features (April 30, 2004)...
On April 30, 2004, I authored a follow-up article: Improving the Content Rater. The newer article examines how to add two features to the content rater: a means to show users the highest rated items, and a page that shows all ratings and comments made, grouped by content item. Read on to learn more!

Conclusion


In this article we looked at a simple User Control to allow users to rate content on your Web site. The rating User Control allows users to give a rating between 1 and 5, and displays an average rating along with a graph showing the rating history for the content item. The User Control employs cookies to remember whether or not a particular user has already rated this content item. While this method can easily be abused by a savvy user to rate a single content item more than once, it was chosen because of ease of implementation and the fact that the content rating system need not be infallible.

Once you have implemented this content rater on your site, you can add all sorts of other interesting features. For example, you could have a page that listed the 10 most popular content items. You might also find it useful to build an administrative Web page that listed the ratings for each content item, along with their comments, to give site editors a quick pulse on their readers' preferences. If you think of any other nifty way to extend this functionality, be sure to let me know!

Happy Programming!

  • By Scott Mitchell


    Attachments


  • Download the User Control and Database Scripts (in ZIP format)



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article