How to build RSS feed using LINQ to SQL

I was watching PDC 2008 and Chris Anderson and Don Box mentioned their presentation on PDC 2006 about LINQ and RSS feeds. They were using SyndicationFeed class, which is new in .NET 3.5. Currently my own RSS feed was constructed manually using old XmlDocument class. LINQ to SQL and Syndication class aproach is more elegant and easy.

Here is my database structure:

Article Schema

Let's load articles first. First we need to disable deferred loading (DeferredLoadingEnabled = false), then we need to make sure that Category would be populated: opt.LoadWith<Article>(a => a.Category).

public static List<Article> GetArticles(int count)

{

    using (SQLDataContext db = new SQLDataContext())

    {

        db.DeferredLoadingEnabled = false;

        System.Data.Linq.DataLoadOptions opt = new System.Data.Linq.DataLoadOptions();

        opt.LoadWith<Article>(a => a.Category);

        db.LoadOptions = opt;

        return db.Articles.Take(count).OrderByDescending(a => a.CreationDate).ToList();

    }

}

Execution of this method is going to produce following SQL:

SELECT [t2].[Id], [t2].[FileName], [t2].[Title], [t2].[ShortDescription], [t2].[Description], [t2].[CreationDate], [t2].[CategoryId], [t2].[Keywords], [t2].[Active], [t2].[CategoryId2], [t2].[Name], [t2].[Description2], [t2].[MetaDescription], [t2].[MetaKeywords]

FROM (

    SELECT TOP (15) [t0].[Id], [t0].[FileName], [t0].[Title], [t0].[ShortDescription], [t0].[Description], [t0].[CreationDate], [t0].[CategoryId], [t0].[Keywords], [t0].[Active], [t1].[CategoryId] AS [CategoryId2], [t1].[Name], [t1].[Description] AS [Description2], [t1].[MetaDescription], [t1].[MetaKeywords]

    FROM [dbo].[Article] AS [t0]

    INNER JOIN [dbo].[Category] AS [t1] ON [t1].[CategoryId] = [t0].[CategoryId]

    ) AS [t2]

ORDER BY [t2].[CreationDate] DESC

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1

 

Not bad, just one sql statement.

Now lets write a core of RSS feed. Let's create simple asp.net page. Just delete everything from aspx page.

<%@ Page Language="C#" AutoEventWireup="true" Inherits="RSS_Recent_Articles" Codebehind="RSS-Recent-Articles.aspx.cs" %>

 

Then codebehind file would look like this:

 

#region UI Handlers

 

    protected void Page_Load(object sender, EventArgs e)

    {

        SyndicationFeed feed = new SyndicationFeed()

        {

            Title = new TextSyndicationContent("Viktar Karpach Web Developer Blog about ASP.NET,C#,T-SQL,Javascript,CSS,Silverlight"),

            Language = "en-us",

            Description = new TextSyndicationContent("Viktar Karpach Web Developer Blog about ASP.NET,C#,T-SQL,Javascript,CSS,Silverlight. New technics and tehnlogies reviews."),

            Generator = "Karpach Web Developer Blog"

        };               

        List<SyndicationItem> items = new List<SyndicationItem>();

        foreach (Article a in Db.GetArticles(15))

        {

            SyndicationItem item = new SyndicationItem();

            item.AddPermalink(new Uri(Utils.GetAbsolutePath(a.FileName)));

            item.Title = new TextSyndicationContent(a.Title);                                   

            item.Summary = new TextSyndicationContent(a.Description,TextSyndicationContentKind.Html);

            item.PublishDate = a.CreationDate;

            item.LastUpdatedTime = a.CreationDate;

            item.Copyright = new TextSyndicationContent("Copyright (c) 2007 Viktar Karpach");

            item.Categories.Add(new SyndicationCategory(a.Category.Name));           

            items.Add(item);

        }

        feed.Items = items;

 

        Rss20FeedFormatter formater = new Rss20FeedFormatter(feed);

        XmlWriter xml = XmlWriter.Create(Response.OutputStream);

        formater.WriteTo(xml);

        xml.Flush();

        Response.Cache.SetExpires(DateTime.Now.AddHours(12));

        Response.Cache.SetCacheability(HttpCacheability.Public);

        Response.Cache.SetValidUntilExpires(false);

 

    }   

 

    #endregion  

 

kick it on DotNetKicks.com

Sunday, November 09, 2008 | Add Comment

Consolas - coder font for Visual Studio 2005-2008

I recently discovered for myself Consolas font. I didn't like it right away. However after 5 min of usage I fell in love with it. Just change default size from 10 to 11 points.

Consolas is a cleartype font designed specifically for to make code more readable is now available for download for users of Visual Studio 2005-2008 from the Microsoft Download Center.

Consolas is intended for use in programming environments and other circumstances where a monospaced font is specified. All characters have the same width, like old typewriters, making it a good choice for personal and business correspondence. Optimizing the font specifically for ClearType allowed a design with proportions closer to normal text than traditional monospaced fonts like Courier. This allows for more comfortable reading of extended text on-screen.

The package will change the default text face in Visual Studio to the Consolas family.

Monday, October 27, 2008 | Add Comment

How to switch between view source and markup view in Visual Studio?

This is strange, but F7 key in Visual Studio switches to code view, but doesn't switch back to markup view. There is no way to switch to markup view unless you open aspx or ascx file directly. This little macros was found by me on web. I had to fix it a little bit, so it works in Visual Studio 2008.

Sub ToggleAspNetCodeBehindFile()

    'Add file extensions here

 

    Dim langExtension() As String = {".cs", ".vb", ".jsl"}

 

    Dim activeDoc As String

    Try

        activeDoc = LCase(ActiveDocument().FullName)

 

        If (InStr(activeDoc, ".aspx") Or _

            InStr(activeDoc, ".ascx") Or _

            InStr(activeDoc, ".asmx") Or _

            InStr(activeDoc, ".asax")) Then

 

            ' Add additional file extensions here

 

            Dim i As Integer

            Dim isCodeBehind As Boolean = False

            Dim extensionLength As Integer = 0

 

            For i = 0 To langExtension.Length - 1

                If activeDoc.EndsWith(langExtension(i)) Then

                    isCodeBehind = True

                    extensionLength = langExtension(i).Length

                    Exit For

                End If

            Next

 

            If (isCodeBehind) Then

                OpenAspNetFile(activeDoc, extensionLength)

            Else

                OpenCodeBehindFile(activeDoc)

            End If

            Exit Sub

        End If

    Catch

        MsgBox("Please select an ASP.NET document to toggle.", _

            MsgBoxStyle.OKOnly, "No ASP.NET Document Selected")

    End Try

End Sub

 

'Description: Opens an aspx, ascx, asax file

 

Private Sub OpenAspNetFile(ByVal activeDoc As String, _

    ByVal extensionLength As Integer)

 

    Dim fileName As String

 

    Dim projItem As ProjectItem

 

    ' .asax or .asmx file

 

    ' Close document if in design mode and open code view

 

    If (InStr(activeDoc, ".asax") Or InStr(activeDoc, ".asmx")) Then

        If (InStr(DTE.ActiveWindow.Caption, "design", _

            CompareMethod.Text)) Then

 

            ActiveDocument.Close(vsSaveChanges.vsSaveChangesPrompt)

        End If

        projItem = DTE.Solution.FindProjectItem(activeDoc)

        projItem.Open(Constants.vsViewKindCode).Activate()

    Else

        fileName = Left(activeDoc, activeDoc.Length - extensionLength)

        Try

            projItem = DTE.Solution.FindProjectItem(fileName)

            projItem.Open(Constants.vsViewKindTextView).Activate()

        Catch

            MsgBox(ActiveDocument().Name & " is not a valid " _

                & "Code-Behind file.", MsgBoxStyle.OKOnly, _

                "ASP.NET file not found")

        End Try

    End If

End Sub

 

'Description: Opens the code behind file

 

Private Sub OpenCodeBehindFile(ByVal activeDoc As String)

    Dim projItem As ProjectItem

 

    projItem = DTE.Solution.FindProjectItem(activeDoc)

    projItem.Document.DTE.ExecuteCommand("View.ViewCode")

 

End Sub

Tuesday, September 30, 2008 | Add Comment