Introduction
I developed a blog (http://www.pushingback.com) for one of Lockheed Martin's civilian government agency clients using Community Server 2.0. One of a number of nice features the product offers is a blog aggregation page that displays the most viewed and most commented-on blog posts in separate sidebar widgets in descending order. One of our project requirements was to implement this functionality for the single blog we're doing. Since Community Server 2.0 didn't offer this feature out of the box at the time, it meant I would have to build it.
Background
Community Server 2.0 combines a number of previously-separate, Open-Source projects on the .NET platform that provides blogging, forums, photo gallery, and other functionality. The vendor, Telligent Systems, markets it as a platform for collaboration and knowledge management. The product can be customized quite significantly because virtually all the source is open. Lockheed Martin used an earlier version (Community Server 1.1) to build an extranet for the nation's AMBER Alert coordinators.
Features
- Number of links displayed can be set via a tag attribute
- Title length can be shortened via a tag attribute
Developing the Code
The most flexible way to customize the look-and-feel of a Community Server blog is to develop a theme. Once you've installed Community Server 2.0 on your machine, the [installdir]\Web\Themes\Blogs folder provides nine sample themes for you to choose from. I needed a three-column layout for this blog, so I copied the "Marvin3" theme to a new folder. We'll name the folder "MyBlog" for the purpose of this article.
The next step was to modify LayoutTemplate.ascx so it would display the "most viewed" widget on the blog. Once modified, the HTML for the right-hand column looked like this:
<div id="sidebar-b">
<Blog:WeblogCalendar runat="Server" id="Cal" />
<Blog:SingleWeblogSearch runat="Server" id="sw" NAME="sw"/>
<Blog:CategoryList ResourceTitleName = "Weblog_PostCategories_Label"
runat="Server" id="Categorylist1"/>
<MBC:MostViewed runat="server" id="mv" PageSize="3" />
<Blog:Subscriptions runat="Server" id="subs" />
</div>
As you can see from this tag prefix:
<%@ Register TagPrefix="MBC"
Namespace="MyBlogControls" Assembly="MyBlogControls" %>
I chose to store the logic for the control in a separate assembly. The primary reason for this was the number of custom controls this project required. In the vast majority of cases, the core controls of Community Server 2.0 are also built in this fashion.
After modifying LayoutTemplate.ascx, I needed to create a skin for the MostViewed
tag to retrieve. By convention, skin files in Community Server are named "Skin-[skin name].ascx", so I created a file named Skin-MostViewed.ascx. Here's the entire file:
<%@ Register TagPrefix="CS" Namespace="CommunityServer.Controls"
Assembly="CommunityServer.Controls" %>
<%@ Control Language="C#" %>
<h3><CS:ResourceControl id="MostViewed"
runat="Server" ResourceName="MostViewed" /></h3>
<ul>
<asp:Repeater Runat="server" ID="posts">
<ItemTemplate>
<li>
<asp:HyperLink Runat="server" id="TitleLink" />
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
I placed the Repeater
inside unordered list tags and the HyperLink
control between list item tags so the stylesheet would format them in a way that matched the other controls in the column. Without the additional tags, the links displayed as left-justified, instead of lining up with the other links in the right-hand column.
With Skin-MostViewed.ascx complete, the work remaining was the logic to retrieve the most-viewed blog posts and bind them to the Repeater
in the skin. Most of the code for actually retrieving the appropriate blog posts came from reading core source code of Community Server and a few extremely useful posts by Keyvan Nayyeri. Here's the code that actually gets the appropriate posts:
private WeblogPost[] GetMostViewedPosts(int PageCount)
{
Weblog weblog = Weblogs.GetWeblog(CSContext.Current.ApplicationKey);
BlogThreadQuery query = new BlogThreadQuery();
query.SectionID = weblog.SectionID;
query.SortBy = BlogThreadSortBy.MostViewed;
query.SortOrder = SortOrder.Descending;
query.PageSize = PageCount;
query.PageIndex = 0;
ThreadSet posts = WeblogPosts.GetBlogThreads(query);
ArrayList al = new ArrayList(posts.Threads.Count);
foreach(WeblogPost p in posts.Threads)
{
al.Add(p);
}
return (WeblogPost[])al.ToArray(typeof(WeblogPost));
}
The array returned by this function is the data source that will be bound to the Repeater
in Skin-MostViewed.ascx. When I was testing my code, I found that if query.SectionID
isn't set to weblog.SectionID
, the links that display will be for the entire Community Server installation, instead of the selected blog. The PageCount
parameter allows the developer to set how many "most viewed" posts are displayed. Rather than hard code a value, I created a public PageSize
property which could be set to the desired value using a tag attribute.
GetMostViewedPosts
must be called before data is bound. In order to ensure this, the MostViewed
class overrides AttachChildControls
and DataBind
. It also contains an event handler for setting specific attributes of the HyperLink
in Skin-MostViewed.ascx. One useful feature the custom control provides is the ability to set how many characters of the blog post title are displayed in the control. Here's the snippet of code from the event handler that controls this:
if (TitleTextLength > 0)
{
titleLink.Text = Formatter.CheckStringLength(post.Subject, TitleTextLength);
titleLink.NavigateUrl = BlogUrls.Instance().Post(post);
titleLink.ToolTip = post.Subject;
}
Conclusion
The MostViewed
control provides a useful enhancement to individual blogs in Community Server 2.0. If Telligent hasn't already built this functionality into the as-yet-unlaunched Community Server 2.1, I will probably do so for ease of use on future projects.