I will accomplish this using two different examples of response, one with a return type of System.ServiceModel.Channels.Message and another with a return type of SyndicationFeedFormatter. First, we need to syndicate a feed based on our data repository. I am including the ability to filter our feed based on genre and artist so we can access virtual sub-feeds with a uri.
private SyndicationFeed CreateAlbumFeed(String genre = "all", String artist = "all")
{
SyndicationFeed feed = new SyndicationFeed
{
Title = SyndicationContent.CreatePlaintextContent("The album listing"),
Description = SyndicationContent.CreatePlaintextContent("Dynamic feed response from single WCF"),
LastUpdatedTime = DateTime.Now,
Items = from a in DataRepository.Albums()
where ((genre.ToLower().CompareTo("all") == 0)||(a.Genre == genre)) &&
((artist.ToLower().CompareTo("all") == 0) || (a.Artist == artist))
select new SyndicationItem
{
LastUpdatedTime = DateTime.Now,
Title = SyndicationContent.CreatePlaintextContent(a.Artist+": "+a.Name),
Content = SyndicationContent.CreateXmlContent(a)
}
};
return feed;
}
[OperationContract]
[WebGet(UriTemplate = "/Feeds/Albums"),
Description("Returns an Atom or RSS feed of albums")]
System.ServiceModel.Channels.Message GetAlbumFeed();
[OperationContract]
[WebGet(UriTemplate = "/Feeds/Genre/{genre}"),
Description("Returns an Atom or RSS feed of albums by genre")]
SyndicationFeedFormatter GetGenreFeed(String genre);
[OperationContract]
[WebGet(UriTemplate = "/Feeds/Artist/{artist}"),
Description("Returns an Atom or RSS feed of albums by artist")]
SyndicationFeedFormatter GetArtistFeed(String artist);
The return type of System.ServiceModel.Channels.Message is very generic and allows for you to simply build the response of a web request. While generic and flexible, it does limit you by not allowing parameters on the REST uri. In order to allow a SyndicationFeedFormatter return type, we must ensure that the service can serialize it as a result. This is achieved by making it a known type for the service by decorating the interface as follows.
[ServiceKnownType(typeof(Atom10FeedFormatter))]
[ServiceKnownType(typeof(Rss20FeedFormatter))]
At this point, it comes down to dynamically formatting your response. We do this by implicitly checking the Content-Type value of the request header in the body of our service methods. Here is one example:
public SyndicationFeedFormatter GetGenreFeed(String genre)
{
SyndicationFeed feed = CreateAlbumFeed(genre: genre);
if (WebOperationContext.Current.IncomingRequest.Headers.Get("Content-Type") != null)
{
if (WebOperationContext.Current.IncomingRequest.Headers.Get("Content-Type").ToLower().Contains("application/atom"))
return new Atom10FeedFormatter(feed);
else
return new Rss20FeedFormatter(feed);
}
return new Rss20FeedFormatter(feed);
}
Now we are able to browse to our URI and see a feed for all albums, albums by artist and albums by genre.
The added ability to select the method in which the client consumes your feed is valuable to ensure all consumers are included. Download the project here
No comments:
Post a Comment