September 2007 - Posts - Raj Kaimal

September 2007 - Posts

SQL 2005 - Maximum number of characters displayed in each column

This setting in Microsoft SQL server management studio, which has a default setting of 256 characters, caused me to waste almost half an hour yesterday. I was looking in the wrong places trying to troubleshoot my stored procedure and wondering why my data was being truncated. There is no indication in management studio that the text was being truncated either.

To increase the maximum value, open SQL Server management studio and go to

 Tools » Options » Query Results » Results to Text » Maximum number of characters displayed in each column

Note also that there is a "Maximum Characters Retrieved" section under "Results to Grid" section too.

Posted by rajbk | 1 comment(s)
Filed under: ,

Building an RSS feed using LINQ to XML and LINQ to SQL

Version : VS 2008 Beta 2

In this post, I am going to show you how to build a RSS feed of the employees in the NorthWind database using LINQ. Before you proceed, you may want to read Scott's introduction of LINQ to XML over here if you haven't done so already.

To start, lets look at how we can programmatically create the XML document below:

 1: <?xml version="1.0" encoding="utf-8" ?>
 2: <Employees>
 3: <Employee>
 4: <Name>Tom</Name>
 5: <ID>1</ID>
 6: </Employee>
 7: <Employee>
 8: <Name>Jane</Name>
 9: <ID>2</ID>
 10: </Employee>
 11: </Employees>

Without LINQ, we could use the XmlDocument class to create an in-memory tree representation of the document above and write it to the HttpResponse stream like so:

 1: XmlDocument doc = new XmlDocument();
 2:  
 3: XmlDeclaration xmldec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
 4: XmlElement root = doc.DocumentElement;
 5: doc.InsertBefore(xmldec, root);
 6:  
 7: XmlElement employees = doc.CreateElement("Employees");
 8: doc.AppendChild(employees);
 9:  
 10: XmlElement employee1 = doc.CreateElement("Employee");
 11: employees.AppendChild(employee1);
 12:  
 13: XmlElement empID1 = doc.CreateElement("ID");
 14: empID1.InnerText = "1";
 15: employee1.AppendChild(empID1);
 16:  
 17: XmlElement empName1 = doc.CreateElement("Name");
 18: empName1.InnerText = "Tom";
 19: employee1.AppendChild(empName1);
 20:  
 21: XmlElement employee2 = doc.CreateElement("Employee");
 22: employees.AppendChild(employee2);
 23:  
 24: XmlElement empID2 = doc.CreateElement("ID");
 25: empID1.InnerText = "2";
 26: employee1.AppendChild(empID2);
 27:  
 28: XmlElement empName2 = doc.CreateElement("Name");
 29: empName2.InnerText = "Jane";
 30: employee2.AppendChild(empName2);
 31:  
 32: Response.Clear();
 33: doc.Save(Response.Output);
 34: Response.End();

LINQ provides a easier and cleaner way to create XML documents known as functional construction. Using functional construction, you can create all or parts of your in-memory XML tree in a single statement. This is made possible by a constructor in the XElement and XDocument classes that take in a params object (FYI, XElement and XDocument both inherit from type XContainer).

 1: public XElement(XName name, params object[] content);
 2: public XDocument(XDeclaration declaration, params object[] content);

The constructor calls an internal method called AddContentSkipNotify to validate the type of object passed into the params object. From the documentation, parameters can be any of the following:

  • A string, which is added as text content. This is the recommended pattern to add a string as the value of an element; the LINQ to XML implementation will create the internal XText node.
  • An XText, which can have either a string or CData value, added as child content.  This is mainly useful for CData values; using a string is simpler for ordinary string values.
  • An XElement, which is added as a child element
  • An XAttribute, which is added as an attribute
  • An XProcessingInstruction or XComment, which is added as child content
  • An IEnumerable, which is enumerated, and these rules are applied recursively
  • Anything else, ToString() is called and the result is added as text content
  • null, which is ignored

Using functional construction, we can create our in memory XML tree and write it to the response stream like so:

   1: XDocument doc = new XDocument(
   2:     new XDeclaration("2.0", "utf-8", "yes"),
   3:         new XElement("Employees",
   4:             new XElement("Employee",
   5:                 new XElement("Name", "Tom"),
   6:                 new XElement("ID", "1")),
   7:             new XElement("Employee",
   8:                 new XElement("Name", "Tom"),
   9:                 new XElement("ID", "1"))));
  10:  
  11: Response.Clear();
  12: doc.Save(Response.Output);
  13: Response.End();

This code is easier to write compared to the XmlDocument method. It is also easy see the underlying structure of the XML document by looking at the code.

From the documentation above, we know that if we pass in IEnumerable<T> to the XElement constructor, it will get enumerated and the rules will be applied recursively to each element in the collection.

With this knowledge, we could rewrite the code above with a LINQ TO XML query that returns an IEnumerable<XElement> from a collection of anonymous types like so:

   1:         var employees = new[] {
   2:             new {Name = "Tom", ID = 1},
   3:             new {Name = "Jane", ID = 2}
   4:         };
   5:  
   6:         XDocument doc = new XDocument(
   7:             new XDeclaration("2.0", "utf-8", "yes"),
   8:                 new XElement("Employees",
   9:                         //LINQ query that returns IEnumerable<XElement>
  10:                         from e in employees
  11:                         select new XElement("Employee",
  12:                             new XElement("Name", e.Name),
  13:                             new XElement("ID", e.ID)
  14:                         )
  15:                 )
  16:         );
  17:  
  18:         Response.Clear();
  19:         doc.Save(Response.Output);
  20:         Response.End();

Note that  "var employees" above is a collection of anonymous types. The output of this code will produce the same XML document like the previous two code samples did.

Instead of the hard coded employee collection, we could use a LINQ to SQL query that returns an IEnumerable<XElement> of employee names and their description from the database. That is the basic idea behind this post - Using LINQ to SQL to query the database, construct an in-memory XML tree using LINQ to XML by following the RSS specification and finally writing it out to the HttpResponse stream.

The XDocument we are going to construct will follow the RSS 2.0 specification (the minimum required) below:

   1: <?xml version="1.0" encoding="utf-8" standalone="yes"?>
   2: <rss version="2.0">
   3:   <channel>
   4:     <title></title>
   5:     <link></link>
   6:     <description></description>
   7:     <item>
   8:       <title></title>
   9:       <description></description>
  10:       <link></link>
  11:     </item>
  12:     ...
  13:     ...
  14:     ...
  15:     <item>
  16:       <title></title>
  17:       <description></description>
  18:       <link></link>
  19:     </item>
  20:   </channel>
  21: </rss>

Assuming we have created our Nortwind LINQ to SQL object model, we can write the final code in 25 lines(!) like this:

   1:     protected void Page_Load(object sender, EventArgs e)
   2:     {
   3:         NorthwindDataContext context = new NorthwindDataContext();
   4:         Response.Clear();
   5:         Response.ContentType = "text/xml";
   6:  
   7:         XDocument document = new XDocument(
   8:             new XDeclaration("1.0", "utf-8", null),
   9:             new XElement("rss",
  10:                 new XElement("channel",
  11:                     new XElement("title", "Employees of Northwind Traders Inc."),
  12:                     new XElement("link", "http://www.northwindtraders.com"),
  13:                     new XElement("description", "Employees of Northwind Traders Inc. ordered by last name."),
  14:                             from emp in context.Employees
  15:                             orderby emp.LastName
  16:                             select new XElement("item",
  17:                                 new XElement("title", emp.LastName + ", " + emp.FirstName),
  18:                                 new XElement("description", emp.Notes),
  19:                                 new XElement("link", "http://www.northwindtraders.com/employees.aspx?id=" + emp.EmployeeID)
  20:                             )
  21:                     ),
  22:                 new XAttribute("version", "2.0")));
  23:         document.Save(Response.Output);
  24:         Response.End();
  25:     }

Note that the LINQ to SQL query fetches the employee name (LastName + FirstName columns) and the Notes column and creates an XElement called "title" and "description" respectively. We also create a dummy "link" node that points to www.northwindtraders.com since it is part of the requirement of the RSS specs. Once we have our XDocument created, we clear the Response stream, set the content type to text/xml and then "Save" the document to the HttpResponse stream.

This is not the optimal solution though since the DB is queried everytime the page is requested. We obviously have to cache the results on the server for a set amount of time. This can easily be done by calling the .ToList() extension method on the XDocument and storing the results in Cache. I show an example of how to cache the results of a LINQ query here

Note also that you should always HtmlEncode data before rendering it on the browser (which is not shown in the sample code). 

I hope this post has shown you how super easy it is to create XML documents from content in the database using LINQ. To learn more, download VS 2008 Beta 2 and check out the LINQ samples.

Posted by rajbk | with no comments
Filed under: , , ,

Using the ListView in tiled mode (Part 2) - CSS layout

Using the ListView in tiled mode (Part 1)

Updated 12/01/2007 for VS 2008 RTM

In this second part of my post on customizing the ListView UI, we are going to look at how to consume a Flickr RSS feed and display the feed items in a ListView (tiled mode). The layout will be done using only CSS (no tables). We will also make use of the new DataPager control to display a pager at the top and bottom of the page. Each page will contain 9 photos with 3 photos per row.

flickrtolistview

I am using an RSS feed of some nice photos from Wagner Campelo (I don't know the guy but found him while looking for photos on flickr for this post).

To get started, we add a ListView control and LinqDataSource control to the page and set the DataSource property of the ListView control to the LinqDataSource. We then implement an event handler to handle the Selecting event of the Linqdatasource. We do this to write a custom LINQ expression in the code behind which will fetch the RSS feed and extract the fields we are interested in. This data is assigned to the Result property of the LinqDataSourceSelectEventArgs object. The code behind is shown below:

 1: protected void LinqDataSource1_Selecting(object sender, LinqDataSourceSelectEventArgs e)
 2: {
 3: XDocument rssFeed = XDocument.Load("http://api.flickr.com/services/feeds/photos_public.gne?id=86361978@N00&tags=colors&lang=en-us&format=rss_200");
 4: e.Result = from item in rssFeed.Descendants("item")
 5: select new
 6: {
 7: Title = item.Element("title").Value,
 8: Description = item.Element("description").Value
 9: };
 10: }

Note that we have written an LINQ expression that enumerates all root "item" nodes and extracts the "title" and "description" node values. To learn more about this, read Scott's tutorial on LINQ to XML

The code above is going to parse the RSS feed every time a post back occurs making it non-optimal. What we should do instead is to cache the result of the RSS feed for a set amount of time. The code can be refactored to support caching like so:

 1: public partial class _Default : System.Web.UI.Page
 2: {
 3: private const string FeedUrl = "http://api.flickr.com/services/feeds/photos_public.gne?id=86361978@N00&tags=colors&lang=en-us&format=rss_200";
 4: private const string PhotoCache = "photoCache";
 5:  
 6: protected void LinqDataSource1_Selecting(object sender, LinqDataSourceSelectEventArgs e)
 7: {
 8: e.Result = GetFlickrFeed();
 9: }
 10:  
 11: private object GetFlickrFeed()
 12: {
 13: Object o = Cache[PhotoCache];
 14: if (o == null)
 15: {
 16: XDocument rssFeed = XDocument.Load(FeedUrl);
 17: var photos = from item in rssFeed.Descendants("item")
 18: select new
 19: {
 20: Title = item.Element("title").Value,
 21: Description = item.Element("description").Value
 22: };
 23: o = photos.ToList();
 24: UpdateRefreshDate();
 25: //We are caching for 5 seconds only for demonstration purposes
 26: Cache.Insert(PhotoCache, o, null, DateTime.Now.AddSeconds(5), Cache.NoSlidingExpiration);
 27: }
 28: return o;
 29: }
 30:  
 31: /// <summary>
 32: /// Update the label control in the list view with 
 33: /// the last refreshed time.
 34: /// </summary>
 35: private void UpdateRefreshDate()
 36: {
 37: Label lblLastRefresh = (Label)ListView1.FindControl("lblLastRefresh");
 38: lblLastRefresh.Text = "Last Refreshed at " + DateTime.Now.ToString();
 39: }
 40: }

Note that we call the ToList() method to evaluate the LINQ expression and create a List<T> from the result. Without doing this, we would have stored the Linq expression in cache which would defeat the purpose.

The ListView control supports paging by associating one or more DataPager controls with it. The DataPager, a new control is the default paging control for the ListView control. It can be placed either inside or outside the ListView control. When placed outside the ListView control, you have to specify the ListView Control whose data you wish to page by specifying the PagedControlID property like so: PagedControlID="ListView1". When placed inside a ListView control, you do not need to specify this property - it is implied. The DataPager control is flexible in how you want the pager UI to look like. Note that you can have as many DataPagers as you want placed anywhere on the page!

Moving on to the UI. The code for the aspx page is shown below:

   1: <asp:ListView ID="ListView1" runat="server" GroupItemCount="3" DataSourceID="LinqDataSource1">
   2:     <GroupSeparatorTemplate>
   3:         <div class="groupSeperator">
   4:         </div>
   5:     </GroupSeparatorTemplate>
   6:     <GroupTemplate>
   7:         <div id="itemPlaceholder" runat="server">
   8:         </div>
   9:     </GroupTemplate>
  10:     <ItemTemplate>
  11:         <span class="itemStyle">
  12:             <div class="photoHeading">
  13:                 <%#Eval("Title") %>
  14:             </div>
  15:             <%#Eval("Description") %>
  16:         </span>
  17:     </ItemTemplate>
  18:     <EmptyItemTemplate>
  19:         <span class="itemStyle"></span>
  20:     </EmptyItemTemplate>
  21:     <AlternatingItemTemplate>
  22:         <span class="altItemStyle">
  23:             <div class="photoHeading">
  24:                 <%#Eval("Title") %></div>
  25:             <%#Eval("Description") %></span>
  26:     </AlternatingItemTemplate>
  27:     <LayoutTemplate>
  28:         <div class="layoutRegion">
  29:             <div class="headingRegion">
  30:                 Wagner Campelo
  31:                 <div class="subHeading">
  32:                     Photos from Flickr
  33:                 </div>
  34:             </div>
  35:             <div class="pagerRegion">
  36:                 <asp:DataPager ID="DataPager1" runat="server" PageSize="6">
  37:                     <Fields>
  38:                         <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True"
  39:                             ButtonCssClass="pagerBtn" FirstPageText=" « " NextPageText=" › " PreviousPageText=" ‹ "
  40:                             LastPageText=" » " />
  41:                     </Fields>
  42:                 </asp:DataPager>
  43:             </div>
  44:             <div id="groupPlaceholder" runat="server">
  45:             </div>
  46:             <div class="pagerRegion">
  47:                 <asp:DataPager ID="DataPager2" runat="server" PageSize="6">
  48:                     <Fields>
  49:                         <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True"
  50:                             ButtonCssClass="pagerBtn" FirstPageText=" « " NextPageText=" › " PreviousPageText=" ‹ "
  51:                             LastPageText=" » " />
  52:                     </Fields>
  53:                 </asp:DataPager>
  54:             </div>
  55:             <div class="footerRegion">
  56:                 Copyright © 2007 | 
  57:                 <asp:Label ID="lblLastRefresh" runat="server"></asp:Label>
  58:             </div>
  59:         </div>
  60:     </LayoutTemplate>
  61:     <ItemSeparatorTemplate>
  62:         <div class="itemSeperator">
  63:         </div>
  64:     </ItemSeparatorTemplate>
  65: </asp:ListView>
  66: <asp:LinqDataSource ID="LinqDataSource1" runat="server" OnSelecting="LinqDataSource1_Selecting">
  67: </asp:LinqDataSource>

Note that I am using only div and span tags in the markup and that all div and span tags have a class attribute associated with it. With an aspx markup like this, you have full control of what the UI will look like by making changes to the respective classes in the CSS file.

You can see that the ListView has the GroupItemCount property set to 3 and that I have added two DataPager controls in the LayoutTemplate.

In the UI, I have used dotted lines to separate each photo and each group using CSS. The bottom right of the sample page displays the last time the data was refreshed. To see what the final result will look like, download the sample project file from either location below:

Location 1
Location 2

Posted by rajbk | 4 comment(s)
Filed under: ,

Using the ListView control in Tiled mode (Part 1)

Version : VS 2008 RTM

The ListView control is a data bound control new to the ASP.net web controls collection. The ListView control, from a UI standpoint, give