-1

I am developing a ASP.Net Web API project.

There is a requirement to return a ATOM feed on changes to resources in the application.

I have the feed all working but for some reason my feed element is omitting the 'xmlns' element which describes the XML as an ATOM feed.

The desired result is:

<?xml version="1.0" encoding="utf-8" ?>
  <feed xmlns="http://www.w3.org/2005/Atom">
    <title type="text">My Feed</title>
    <id>uuid:ff389357-aaab-4814-8916-b8fff325e6bb;id=22</id>
    <updated>2013-04-11T16:15:10Z</updated>
    <entry>
      <id>uuid:ff389357-aaab-4814-8916-b8fff325e6bb;id=23</id>
      <title type="text">Data.Parliament Resource 1</title>
      <updated>2013-04-11T16:15:10Z</updated>
      <author>
        <name>Parliament System X</name>
      </author>
     </entry>
  </feed>

But my feed looks like:

<?xml version="1.0" encoding="utf-8" ?>
  <feed>
    <title type="text">My Feed</title>
    <id>uuid:ff389357-aaab-4814-8916-b8fff325e6bb;id=22</id>
    <updated>2013-04-11T16:15:10Z</updated>
    <entry>
      <id>uuid:ff389357-aaab-4814-8916-b8fff325e6bb;id=23</id>
      <title type="text">Data.Parliament Resource 1</title>
      <updated>2013-04-11T16:15:10Z</updated>
      <author>
        <name>Parliament System X</name>
      </author>
     </entry>
  </feed>

Notice the missing 'xmlns' attribute on the 'feed' element.

I've searched high and low to no avail...

Question:

Can anyone explain to me why the 'xmlns' element is missing and how to get it back in there???

Here is the code for the ATOM media type formatter:

public class AtomMediaTypeFormatter : BufferedMediaTypeFormatter
{
    private const string AtomMediaType = "application/atom+xml";
    private IFeedHelper _feedService;

    public AtomMediaTypeFormatter(IFeedHelper feedService)
    {
        this._feedService = feedService;
        SupportedMediaTypes.Add(new MediaTypeHeaderValue(AtomMediaType));
        this.AddQueryStringMapping("format", "atom", AtomMediaType);
    }

    public override bool CanWriteType(Type type)
    {
        return type.Implements<IFeedEntry>() || type.Implements<IFeed>();
    }

    /// <summary>
    /// DDP is not currently supporting this operation.
    /// </summary>
    public override object ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Writes the given object value of type <param name="type"></param> to the given stream
    /// </summary>
    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
    {
        using (writeStream)
        {
            var feed = value as IFeed;
            if (feed != null)
            {
                WriteAtomFeed(feed, writeStream);
            }
            else
            {
                WriteAtomEntry((IFeedEntry)value, writeStream);
            }
        }
    }

    private void WriteAtomFeed(IFeed feed, Stream writeStream)
    {
        var formatter = new Atom10FeedFormatter(_feedService.Syndicate(feed));

        using (var writer = XmlWriter.Create(writeStream))
        {
            formatter.WriteTo(writer);
        }
    }

    private void WriteAtomEntry(IFeedEntry feedEntry, Stream writeStream)
    {
        var formatter = new Atom10ItemFormatter(_feedService.Syndicate(feedEntry));

        using (var writer = XmlWriter.Create(writeStream))
        {
            formatter.WriteTo(writer);
        }
    }
}

This is the code for the FeedService.Sydnicate(IFeed) method:

    /// <summary>
    /// Instantiates and returns a SyndicationFeed using the values of the given IFeed instance
    /// </summary>
    public SyndicationFeed Syndicate(IFeed feed)
    {
        var atomFeed = new SyndicationFeed
        {
            Title = new TextSyndicationContent(feed.Title),
            Id = feed.Id,
            Items = feed.Items.Select(i => Syndicate(i)),
            LastUpdatedTime = feed.LastUpdated
        };

        atomFeed.Links.Add(new SyndicationLink(new Uri(feed.Link.Href), feed.Link.Href, "", "", default(long)));

        return atomFeed;
    }

And finally the FeedService.Sydnicate(IFeedEntry):

    /// <summary>
    /// Instantiates and returns a SyndicationItem using the values of the given IFeedEntry instance
    /// </summary>
    public SyndicationItem Syndicate(IFeedEntry feedEntry)
    {
        var item = new SyndicationItem
        {
            Id = feedEntry.Id,
            Title = new TextSyndicationContent(feedEntry.Title, TextSyndicationContentKind.Plaintext),
            LastUpdatedTime = feedEntry.LastUpdated
        };
        item.Authors.Add(new SyndicationPerson("", feedEntry.Author, ""));
        if (feedEntry.Links != null)
        {
            foreach (var link in feedEntry.Links)
            {
                item.Links.Add(new SyndicationLink(new Uri(link.ToString())));
            }
        }
        return item;
    }
Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
JTech
  • 3,420
  • 7
  • 44
  • 51

1 Answers1

0

I can't help you with why the Atom10FeedFormatter is not adding the namespace, but if you don't find a solution I may have an alternative. I've played around using the ODataMessageWriter to write Atom content. You can see the source code here and the output (with the namespace) is here.

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • Thanks for sharing Darrel. I'm not understanding quite how I would utilize that code...two things: 1. what calls the ODataResponse IODataView.CreateView() method and 2. upon returning an instantiated LearningViewModel which formatter kicks in to render the body content? – JTech Apr 12 '13 at 08:48
  • @JTech Sorry, I wasn't suggesting you use my approach where the formatter looks for an interface on the viewmodel and calls back into the viewmodel to allow it to render itself. I was simply suggesting a different library for rendering the Atom feed that you could use in your formatter. – Darrel Miller Apr 12 '13 at 11:16