Why does XmlWriter.Create() fail my test with Rss20FeedFormatter and SyndicationFeed?

836 Views Asked by At

The following test below passes only because new XmlTextWriter(sw) is used instead of XmlWriter.Create(sw, settings) or XmlTextWriter.Create(sw):

    public void ShouldGenerateRssFeed()
    {
        //reference: [http://dotnetslackers.com/articles/aspnet/How-to-create-a-syndication-feed-for-your-website.aspx]

        var items = new List<SyndicationItem>
        {
            new SyndicationItem
            {
                Content = TextSyndicationContent.CreatePlaintextContent("This is plain test content for first item."),
                PublishDate = DateTime.Now,
                Summary = TextSyndicationContent.CreatePlaintextContent("Item summary for first item…"),
                Title = TextSyndicationContent.CreatePlaintextContent("First Item Title")
            },
            new SyndicationItem
            {
                Content = TextSyndicationContent.CreatePlaintextContent("This is plain test content for second item."),
                PublishDate = DateTime.Now,
                Summary = TextSyndicationContent.CreatePlaintextContent("Item summary for second item…"),
                Title = TextSyndicationContent.CreatePlaintextContent("Second Item Title")
            },
            new SyndicationItem
            {
                Content = TextSyndicationContent.CreateXhtmlContent("This is <strong>XHTML</strong> test content for <em>third</em> item."),
                PublishDate = DateTime.Now,
                Summary = TextSyndicationContent.CreatePlaintextContent("Item summary for third item…"),
                Title = TextSyndicationContent.CreatePlaintextContent("Third Item Title")
            }
        };

        var feed = new SyndicationFeed(items);

        Assert.IsTrue((new List<SyndicationItem>(feed.Items)).Count == 3, "The expected number of Syndication items is not here.");

        feed.Items.ForEachInEnumerable(i =>
        {
            i.Authors.Add( new SyndicationPerson
            {
                Email = "[email protected]",
                Name = "Bryan Wilhite",
                Uri = "http://SonghaySystem.com"
            });
        });

        var formatter = new Rss20FeedFormatter(feed);

        var settings = new XmlWriterSettings
        {
            Encoding = Encoding.UTF8,
            Indent = true,
            IndentChars = "    "
        };

        var buffer = new StringBuilder();
        var output = string.Empty;

        using(var sw = new StringWriter(buffer))
        {
            var writer = new XmlTextWriter(sw); //XmlWriter.Create(sw, settings) or XmlTextWriter.Create(sw) fails here!
            formatter.WriteTo(writer);
            output = buffer.ToString();
            TestContext.WriteLine(output);
        }

        Assert.IsTrue(!output.Equals(string.Empty), "The expected output is not here.");

    }

By the way, I'm using an extension method, ForEachInEnumerable, in the sample above:

    /// <summary>
/// Extensions for <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/>.
/// </summary>
public static class IEnumerableOfTExtensions
{
    /// <summary>
    /// Performs the <see cref="System.Action"/>
    /// on each item in the enumerable object.
    /// </summary>
    /// <typeparam name="TEnumerable">The type of the enumerable.</typeparam>
    /// <param name="enumerable">The enumerable.</param>
    /// <param name="action">The action.</param>
    /// <remarks>
    /// “I am philosophically opposed to providing such a method, for two reasons.
    /// …The first reason is that doing so violates the functional programming principles
    /// that all the other sequence operators are based upon. Clearly the sole purpose of a call
    /// to this method is to cause side effects.”
    /// —Eric Lippert, “foreach” vs “ForEach” [http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx]
    /// </remarks>
    public static void ForEachInEnumerable<TEnumerable>(this IEnumerable<TEnumerable> enumerable, Action<TEnumerable> action)
    {
        foreach(var item in enumerable)
        {
            action(item);
        }
    }
}
1

There are 1 best solutions below

0
On

I was using the wrong Disposable object: the StringBuilder did not need a StringWriter---and I failed to Flush the XmlWriter (which is a practice that dates back to .NET 2.0):

    [TestMethod]
    public void ShouldGenerateRssFeed()
    {
        //reference: [http://dotnetslackers.com/articles/aspnet/How-to-create-a-syndication-feed-for-your-website.aspx]

        var items = new List<SyndicationItem>
        {
            new SyndicationItem
            {
                Content = TextSyndicationContent.CreatePlaintextContent("This is plain test content for first item."),
                PublishDate = DateTime.Now,
                Summary = TextSyndicationContent.CreatePlaintextContent("Item summary for first item…"),
                Title = TextSyndicationContent.CreatePlaintextContent("First Item Title")
            },
            new SyndicationItem
            {
                Content = TextSyndicationContent.CreatePlaintextContent("This is plain test content for second item."),
                PublishDate = DateTime.Now,
                Summary = TextSyndicationContent.CreatePlaintextContent("Item summary for second item…"),
                Title = TextSyndicationContent.CreatePlaintextContent("Second Item Title")
            },
            new SyndicationItem
            {
                Content = TextSyndicationContent.CreateXhtmlContent("This is <strong>XHTML</strong> test content for <em>third</em> item."),
                PublishDate = DateTime.Now,
                Summary = TextSyndicationContent.CreatePlaintextContent("Item summary for third item…"),
                Title = TextSyndicationContent.CreatePlaintextContent("Third Item Title")
            }
        };

        var feed = new SyndicationFeed(items)
        {
            Description = TextSyndicationContent.CreatePlaintextContent("My feed description."),
            Title = TextSyndicationContent.CreatePlaintextContent("My Feed")
        };

        feed.Authors.Add(new SyndicationPerson
        {
            Email = "[email protected]",
            Name = "Bryan Wilhite",
            Uri = "http://SonghaySystem.com"
        });

        Assert.IsTrue((new List<SyndicationItem>(feed.Items)).Count == 3, "The expected number of Syndication items is not here.");

        feed.Items.ForEachInEnumerable(i =>
        {
            i.Authors.Add(feed.Authors.First());
        });

        var formatter = new Rss20FeedFormatter(feed);

        var settings = new XmlWriterSettings
        {
            CheckCharacters = true,
            CloseOutput = true,
            ConformanceLevel = ConformanceLevel.Document,
            Encoding = Encoding.UTF8,
            Indent =  true,
            IndentChars = "    ",
            NamespaceHandling = NamespaceHandling.OmitDuplicates,
            NewLineChars = "\r\n",
            NewLineHandling = NewLineHandling.Replace,
            NewLineOnAttributes = true,
            OmitXmlDeclaration = false
        };

        var buffer = new StringBuilder();
        var output = string.Empty;
        using(var writer = XmlWriter.Create(buffer, settings))
        {
            formatter.WriteTo(writer); // or feed.SaveAsRss20(writer);
            writer.Flush();
            writer.Close();
            output = buffer.ToString();
        }
        TestContext.WriteLine(output);

        Assert.IsTrue(!output.Equals(string.Empty), "The expected output is not here.");

    }