LINQ and WCF Syndication

I must admit, having survived the last 22 data access technologies, I'm really liking LINQ. The fact that I can use LINQ to query just about anything, against just about any data source is pretty cool. Lists and Arrays beware. Nested Correlated sub-queries are near - I also love to hear Luca speak about it.

Anyway, while preparing the latest DinnerNow release (coming soon), I had to rewrite the RSS feed for the restaurant. Obviously using the Syndication Support in WCF.

Since the Feed is simply returning menu items, you can imagine its a simple database call to return the menu items, then a loop to create syndication feed items for each one, then spit them out. Fine, but with LINQ, you can miss most of that out. In fact when I originally wrote this, it had 1 line of code which returned the results of a LINQ query. Some people thought this might be too much so I split it into many more lines as shown below.

Key in creating the Syndication items is line 15, as part of the LINQ query. The query projects directly into SyndicationItems. Note also the Links property being populated on line 27 - all pretty neat.

Since the feed type (atom or rss) is simply formatting, I actually specified this as a parameter and lines 37 to 39 work out which formatter to use, based upon the URL.

    1:  public System.ServiceModel.Syndication.SyndicationFeedFormatter GetMenuItems(
    2:      string feedType, 
    3:      string restaurantName, 
    4:      string menuType)
    5:  {
    6:       var db = new DinnerNowDataContext();
    7:   
    8:       Uri incomingURI = (OperationContext.Current == null ? 
    9:          new Uri("https://localhost/") : 
   10:          OperationContext.Current.IncomingMessageHeaders.To);
   11:   
   12:       var items = from mi in db.MenuItems.AsEnumerable()
   13:          where ((mi.Menu.Restaurant.Name == restaurantName) && (mi.Menu.MenuType.Trim() == menuType))
   14:          orderby mi.Name
   15:          select new SyndicationItem()
   16:          {
   17:              Title = SyndicationContent.CreatePlaintextContent(mi.Name),
   18:              PublishDate = DateTime.MinValue,
   19:              LastUpdatedTime = DateTime.MinValue,
   20:              Id = mi.MenuId.ToString(),
   21:              Content = new TextSyndicationContent(
   22:          String.Format(
   23:              CultureInfo.CurrentCulture,@"<p>{0}</p><p><img src='{1}/{2}' style='border: 0px;width:216px;height:174px;' /></p>",
   24:                          mi.Description,
   25:                          "/DinnerNow",
   26:                          mi.ImageLocation), TextSyndicationContentKind.Html),
   27:              Links = { SyndicationLink.CreateAlternateLink(new Uri(incomingURI.AbsoluteUri + "/" + mi.Name)) }
   28:           };
   29:   
   30:       SyndicationFeed feed = new SyndicationFeed(
   31:          "DinnerNow - Menu Items",
   32:          "Menu Items for Restaurant",
   33:          incomingURI,
   34:          items.ToList<SyndicationItem>()
   35:          );
   36:   
   37:       return (feedType.ToLower(CultureInfo.CurrentCulture).Equals("atom") ?
   38:          (new Atom10FeedFormatter(feed)) as SyndicationFeedFormatter :
   39:          new Rss20FeedFormatter(feed));
   40:  }

Below is the contract, so you can see how the URL is put together. Something like https://localhost/DinnerNow/service/menussearchservice.svc/rss/restaurants/NorthWind/Dinner would activate the service.

    1:  [OperationContract]
    2:  [WebGet(UriTemplate = @"/{feedType}/restaurants/{restaurantName}/{menuType}")]
    3:  SyndicationFeedFormatter GetMenuItems(string feedType, string restaurantName, string menuType);

Minus the contract, there really is only 5 lines of code - albeit split into multiple lines. Whilst this in itself is not that cool, the fact my code is no longer plagued with mind-numbing foreach loops is an absolute blessing. (re-write the above using ADO.NET if you want to see what I mean)

Long Live LINQ...

Note: this post was never meant to be a tutorial, simply a look how cool this is...

THIS POSTING IS PROVIDED "AS IS" WITH NO WARRANTIES, AND CONFERS NO RIGHTS

EVEN IF YOU HAVE A NOTE FROM YOUR MUM