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.