Mad about .NET A blog from Jose Fco Bonnin


Around one month ago the Comando Tomate interviewed me at the Microsoft facilities "La Finca", thanks to this interview I was able to explain what the projects of Baleares on .NET are and what I do at Ineta Spain.

If you want to know more just take a look (Spanish).

 

March, 28th we celebrated the anniversary of Baleares on .NET.

I would really like to thank all the speakers for coming to such important event for us Eladio Rincón, Juan Manuel Servera, Rodrigo Corral, David Cervigón, Miguel Jiménez and David Salgado.

All of them made possible to host what at the end was an incredible day, I hope they enjoyed as much as I did and that they come to visit us again in a near future.

You can see some of the photos we took here.

The 28th, March the .NUG Baleares on .NET celebrates its first anniversary doing a big launch event. You can see the agenda below:

09:00 - 09:30 Register

09:30 - 10:00 Presentation

10:00 - 11:00 Windows Server 2008 - David Cervigón, Microsoft.

11:00 - 12:00 Agile Methodologies with TFS 2008 - Rodrigo Corral, PlainConcepts.

12:00 - 12:30 Coffee Break

12:30 - 13:30 SQL Server 2008 - Eladio Rincón, SolidQuality Mentors.

13:30 - 14:30 ADO.NET Framework Entity - Jose Fco Bonnin, Payvision.

14:30 - 15:30 Free time to Lunch

15:30 - 16:30 ADO.NET Data Services - Juan Manuel Servera, Babtec.

16:30 - 17:30 Emotional Design and Advanced User Experiences with Silverlight y WPF - Miguel Jiménez, Ilitia.

17:30 - 18:30 Advanced Debugging - David Salgado, Microsoft.

Visit http://www.baleareson.net/communitylaunch for more information.

In the last TTT we had a session to discuss about several things regarding the .NET User Groups and one of the subjects was the MSDN forums.

Microsoft told us that they were investing some efforts to improve the Spanish MSDN forums and immediately after that we talked about the local forums each .NUG has in their sites. The idea proposed was to remove the local forums and to support the MSDN forums, this would benefit the developer community since instead of having microsites we can sum our efforts to have a centralized help site.

In Baleares on .NET we thought that the best was to have our own forums in order to provide better assistance to our community, we wanted to be sure that the .NET developers of Baleares had answers to their questions. Because of that some "volunteers" are monitoring the forums to provide solutions, but as the community grows we can give less support and the idea to post the questions to bigger communities does not seem to be a bad idea.

I must say that I'm not 100% convinced yet that this is best solution for our community, since I trust the "closeness" concept we tried to offer and that had good results until now.

Anyway I've decided to give a try and to introduce progressively some of the MSDN forums in order our users know them. I wanted not only to insert a simple link to the MSDN forums, but to display some of the posts in our website in line with the current appearance. 

To do it, we can save lot of time taking profit of the Community Server platform to add the latest posts in our home page in the same way the Recent Post List appears. If we take a look about how CS displays the recent posts, we can see that it uses the control IndexPostList, which basically consists of display the results of a search done when the page inits. Below you can see the code the guys from CS use:

   1: List<IndexPost> recentPosts = CSCache.Get("HomePageSearch-" + CurrentCSContext.User.RoleKey) as List<IndexPost>;
   2: if (recentPosts == null)
   3: {
   4:     SearchQuery query = new SearchQuery();
   5:     query.StartDate = DateTime.Now.AddDays(-10);
   6:     query.EndDate = DateTime.Now.AddDays(1);
   7:     query.PageSize = 5;
   8:  
   9:     recentPosts = CSSearch.Search(query).Posts;
  10:     CSCache.Insert("HomePageSearch-" + CurrentCSContext.User.RoleKey, recentPosts, CSCache.MinuteFactor * 5);
  11: }
  12: RecentPostList.DataSource = recentPosts;

It doesn't seem too complicated, basically we need to introduce a new IndexPostList control in the main page and set the DataSource property with our own List of IndexPost. All the MSDN ES forums allow to syndicate the content, this means that we can access it via RSS. The easiest way to do this with .NET is to use a XmlTextReader and read the contents inside a DataSet.

As you can see in the code below we also make use of the XslCompiledTransform, this is done because the feeds contain two comments elements, even if they have different namespaces the ReadXml method of the dataset will throw an exception, since it will consider both of them as the same column. I got the idea to use to Transform from the next post, where the author got into the same troubles when loading two "comments" elements from the feed.

   1: XslCompiledTransform rssTransform = new XslCompiledTransform();
   2: rssTransform.Load(xsltPath);
   3:  
   4:  
   5: using (XmlTextReader xmlTextReader = new XmlTextReader(feeds[i].Url))
   6: {
   7:     using (StringWriter stringWriter = new StringWriter())
   8:     {
   9:         XPathDocument rssXPath = new System.Xml.XPath.XPathDocument(xmlTextReader);
  10:         rssTransform.Transform(rssXPath, null, stringWriter);
  11:  
  12:         DataSet ds = new DataSet();
  13:         using (System.IO.StringReader reader = new System.IO.StringReader(stringWriter.ToString()))
  14:         {
  15:             ds.ReadXml(reader);
  16:         }
  17:  
  18:         DataTable dt = ds.Tables["item"];
  19:         int maxItems = feeds[i].MaxItems;
  20:         DateTime maxDate = DateTime.Now.AddDays(feeds[i].MaxDays * -1);
  21:         for (int idx = 0; idx < maxItems && idx < dt.Rows.Count; idx++)
  22:         {
  23:             DateTime postDate = DateTime.Parse((string)dt.Rows[idx]["date"]);
  24:  
  25:             if (postDate >= maxDate)
  26:             {
  27:                 IndexPost post = new IndexPost();
  28:                 post.ApplicationKey = feeds[i].Name;
  29:                 post.ApplicationType = ApplicationType.Forum;
  30:                 post.ApplicationUrl = feeds[i].Url;
  31:                 post.FormattedBody = (string)dt.Rows[idx]["description"];
  32:                 post.PostDate = postDate;
  33:                 post.SectionName = feeds[i].Name;
  34:                 post.Title = (string)dt.Rows[idx]["title"];
  35:                 post.Url = (string)dt.Rows[idx]["link"];
  36:                 post.UserName = (string)dt.Rows[idx]["creator"];
  37:  
  38:                 items.Add(post);
  39:             }
  40:         }
  41:  
  42:     }
  43: }

From lines 27 to 36 we initialize the class IndexPost with the values obtained from the feed, this values are then used by the IndexPostList control and allow some interaction with them like providing links to the post and forum URLs.

Aside loading the XML you will see that I added some extra features to be able to configure a few parameters regarding the posts we will display. This is done via a custom section I added to the web.config that is handled by the classes SectionHandler, FeedConfigurationCollection and FeedConfiguration. These classes will allow us configuring the feeds from which we will get the posts, the maximum number of posts to display per feed and the oldness of them. You can download the source code to see the full implementation. Do not forget to place the new assembly in the bin folder of CS and to set the configuration in the web.config.

Now that we can configure the feeds and to obtain the desired posts we need to modify the page home.aspx for each of the themes supported on our CS. First of all is to add our IndexPostList control with the information to show.

   1: <CSControl:IndexPostList runat="server" ShowHeaderFooterOnNone="false" ID="RecentMsdnPostList">
   2:     <HeaderTemplate>
   3:         <p />
   4:         <h2 class="CommonTitle"><CSControl:ResourceControl ResourceName="default_homepage_msdnrecentposts" runat="server" /></h2>
   5:         <div class="CommonContent">
   6:         <ul class="CommonSearchResultList">
   7:     </HeaderTemplate>
   8:     <ItemTemplate>
   9:         <li>
  10:         <CSControl:IndexPostData runat="server" Property="ApplicationType" Text="&lt;div class=&quot;CommonSearchResultArea Msdn&quot;&gt;" />
  11:             <CSControl:IndexPostData runat="server" Property="Title" LinkTo="Post" Tag="h4" CssClass="CommonSearchResultName" />
  12:             <div class="CommonSearchResult">
  13:                 <CSControl:IndexPostData Property="FormattedBody" runat="server" TruncateAt="350" />
  14:             </div>
  15:             <div class="CommonSearchResultDetails">
  16:                 <CSControl:ResourceControl runat="server" ResourceName="SearchResults_PostTo" />
  17:                 <CSControl:IndexPostData Property="SectionName" LinkTo="Section" runat="server" />
  18:                 <CSControl:IndexPostData Property="ApplicationType" LinkTo="Application" Text="({0})" runat="server" />
  19:                 <CSControl:ResourceControl runat="server" ResourceName="SearchResults_By" />
  20:                 <CSControl:IndexPostData Property="UserName" LinkTo="Nothing" runat="server" />
  21:                 
  22:                 <CSControl:IndexPostData Property="PostDate" runat="server" />
  23:             </div>
  24:         </div>
  25:         </li>
  26:     </ItemTemplate>
  27:     <FooterTemplate>
  28:         </ul>
  29:         </div>
  30:     </FooterTemplate>
  31:     <NoneTemplate></NoneTemplate>
  32: </CSControl:IndexPostList>

The main things to have in consideration is that we added the a new resource default_homepage_msdnrecentposts (file resources.xml of each language) to support several languages and a new css style CommonSearchResultArea.Msdn (file common.css of each theme), with this style we will modify the background image that appears left to the post.

The next step is to load the feeds and to bind the list of posts retrieved to the control, this is done in the OnInit event of the home page.

   1: List<IndexPost> msdnPosts = CSCache.Get("HomePageMsdn-" + CurrentCSContext.User.RoleKey) as List<IndexPost>;
   2: if (msdnPosts == null)
   3: {
   4:     BalearesOnNet.Rss.FeedHelper helper = new BalearesOnNet.Rss.FeedHelper();
   5:     msdnPosts = helper.LoadFeeds(Request.PhysicalApplicationPath + "rssToDataSet.xslt");
   6:     if (msdnPosts.Count > 0)
   7:         CSCache.Insert("HomePageMsdn-" + CurrentCSContext.User.RoleKey, msdnPosts, CSCache.HourFactor);
   8: }
   9: RecentMsdnPostList.DataSource = msdnPosts;

As you can see we also add the retrieved posts to the cache to avoid loading them from MSDN forums each time a user connects to the page, you can play with several factors to find which one fits better with your site.

Below you can see a screenshot of how the posts are displayed or even better just go to Baleares on .NET

 

That's all I hope you liked it.

BalearesOnNetRss.zip (6.73 kb)

This past Friday I was speaking about Silverlight at the .NET User Group: Baleares on .NET.

As always I really enjoyed the meeting and I hope the attendees had a nice time learning some of the features that Silverlight 1.0 and 1.1 bring. For the event, I wanted to do something different and instead of using Power Point to do the slides I created a small Silverlight 1.1 application.

You can see it online at http://www.baleareson.net/silverlight/default.html