Stanza is a book reader for the iPhone/iPad. One of Stanza’s features is the ability to browse specially formatted book catalogs. While it has a number of built-in catalogs, you can also add your own. I have created such a catalog with ASP.Net MVC 2.0 (screenshots). The Stanza catalog format is pretty simple – just AtomPub with some proprietary attributes for images and things like search. This was a quick and easy project because the .Net Framework 4.0 has the System.ServiceModel.Syndication namespace which does all the RSS/Atom feed generation. We just have to add some custom attributes and serialize the feed to the browser.

Here is a quick overview of the code (Links are to the latest version of the source code in my SVN browser. You can get the project from SVN here (guest/guest).) The LiteratureCatalog and LiteratureCatalog.Tests projects have the relevant code.

Update: The Stanza catalog format works equally well with Aldiko, an e-reader for Android.

CatalogController.cs:

This is the default controller specified in global.asax. It defers to MisesFeeds to generate the feed items and to FeedResult to serialize and write out the feed.

Sample Method:

public FeedResult Journal ( int journalId ) { var feeds = new MisesFeeds ( Request ) ; SyndicationFeed feed = feeds . GetJournalFeed ( journalId ) ; return new FeedResult ( new Atom10FeedFormatter ( feed ) ) ; } public FeedResult Journal(int journalId) { var feeds = new MisesFeeds(Request); SyndicationFeed feed = feeds.GetJournalFeed(journalId); return new FeedResult(new Atom10FeedFormatter(feed)); }

MisesFeeds.cs

MisesFeed contains all the code to generate a SyndicationFeed object containing a List of SyndicationItem. Note the Stanza-specific links added in search list-builder and the final helper method:

item . Links . Add ( new SyndicationLink ( new Uri ( DataFormat . GetAbsoluteURL ( p . Logo ) ) , "x-stanza-cover-image-thumbnail" , "" , "image/jpeg" , 0 ) ) ; item.Links.Add(new SyndicationLink(new Uri(DataFormat.GetAbsoluteURL(p.Logo)), "x-stanza-cover-image-thumbnail", "", "image/jpeg", 0));

public SyndicationFeed CreateFeedFromSyndicationItemList ( IEnumerable postItems, string title, string description ) { var feed = new SyndicationFeed ( title, description, new Uri ( feedUri ) , postItems ) { Copyright = new TextSyndicationContent ( Configuration . Copyright ) , Language = "en-US" } ; var self = new SyndicationLink ( new Uri ( Host + HttpUtility . UrlEncode ( "/Catalog/" ) ) , "self" , "" , Type, 0 ) ; feed . Links . Add ( self ) ; feed . Links . Add ( new SyndicationLink ( new Uri ( Host + "/Catalog/Search/?q={searchTerms}" , true ) , "search" , "Search Catalog" ,Type, 0 ) ) ; return feed ; } public SyndicationFeed CreateFeedFromSyndicationItemList(IEnumerable postItems, string title, string description) { var feed = new SyndicationFeed(title, description, new Uri(feedUri), postItems) { Copyright = new TextSyndicationContent(Configuration.Copyright), Language = "en-US" }; var self = new SyndicationLink(new Uri(Host + HttpUtility.UrlEncode("/Catalog/")), "self", "", Type, 0); feed.Links.Add(self); feed.Links.Add(new SyndicationLink(new Uri(Host + "/Catalog/Search/?q={searchTerms}",true),"search","Search Catalog",Type,0)); return feed; }

FeedResult.cs:

FeedWriter inherits from ActionResult. It just writes the SyndicationFeed out with an XmlTextWriter:

public override void ExecuteResult ( ControllerContext context ) { if ( context == null ) throw new ArgumentNullException ( "context" ) ; HttpResponseBase response = context . HttpContext . Response ; response . ContentType = ! string . IsNullOrEmpty ( ContentType ) ? ContentType : "application/atom+xml" ; if ( ContentEncoding != null ) response . ContentEncoding = ContentEncoding ; if ( feed != null ) using ( var xmlwriter = new XmlTextWriter ( response . Output ) ) { xmlwriter . Formatting = Formatting . Indented ; feed . WriteTo ( xmlwriter ) ; } } public override void ExecuteResult(ControllerContext context) { if (context == null) throw new ArgumentNullException("context"); HttpResponseBase response = context.HttpContext.Response; response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/atom+xml"; if (ContentEncoding != null) response.ContentEncoding = ContentEncoding; if (feed != null) using (var xmlwriter = new XmlTextWriter(response.Output)) { xmlwriter.Formatting = Formatting.Indented; feed.WriteTo(xmlwriter); } }

Thanks to DamienG for the FeedResult class.

To see the catalog, get the Stanza app, tap “Get Books”, “Shared”, “Add Book Source”, then add the URL mises.org/catalog.