Utiliser Rss20FeedFormatter et Atom10FeedFormatter avec ASP .net core 3

De base si l'on tente de générer un flux RSS via ASP .net core 3 et un SyndicationFeed, on utilise un code synchrone. Ce qui n'est pas du gout de core 3 et qui va produire des Exceptions.

Voici le code d'un ActionResult personnalisé qui fonctionne parfaitement avec .net core 2.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.ServiceModel.Syndication;
using System.Text;
using System.Xml;

namespace MyLib.Web.Results
{
    public sealed class FeedResult : ActionResult
    {
        #region Declarations

        private const String AtomContentType = "application/atom+xml";
        private const String RssContentType= "application/rss+xml";

        public enum Type
        {            
            Atom,
            Rss
        }

        private readonly SyndicationFeed _feed;
        private readonly Type _type;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="feed"></param>
        public FeedResult(SyndicationFeed feed, Type type)
        {
            _feed = feed;
            _type = type;
        }

        #endregion

        #region Methodes

        public override void ExecuteResult(ActionContext context)
        {
            // Get the response
            HttpResponse response = context.HttpContext.Response;

            // Add settings
            var settings = new XmlWriterSettings
            {
                Encoding = new UTF8Encoding(false)
            };

            // Write
            using (XmlWriter writer = XmlWriter.Create(response.Body, settings))
            {
                if (_type == Type.Atom)
                {
                    response.ContentType = AtomContentType;
                    Atom10FeedFormatter atomformatter = new Atom10FeedFormatter(_feed);
                    atomformatter.WriteTo(writer);
                }
                else
                {
                    response.ContentType = RssContentType;
                    Rss20FeedFormatter rssformatter = new Rss20FeedFormatter(_feed);
                    rssformatter.WriteTo(writer);
                }
            }
        }

        #endregion
    }
}

Pour l'utiliser en réponse d'un Controller, rien de très compliqué

return new FeedResult(yourFeed, FeedResult.Type.Rss);

Pour rendre ce code opérationnel avec .net core 3, il faut que la réponse soit produite par une méthode Async. La solution la plus simple et d'utiliser la méthode WriteAsync de Response et de lui passer une String. Pour cela, on peut passer par un StringBuilder qui va récupérer le produit du XmlWriter. Et pour rester dans l'asynchrone, on peut lui demander d'utiliser ces options asynchrones.

Ce qui donne :

public override async void ExecuteResult(ActionContext context)
{
    // Get the response
    HttpResponse response = context.HttpContext.Response;

    // Add settings
    var settings = new XmlWriterSettings
    {
        Encoding = new UTF8Encoding(false),
        Async = true
    };

    // Write
    String content;
    using (StringWriter stringWriter = new StringWriter())
    using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
    {
        if (_type == Type.Atom)
        {
            response.ContentType = AtomContentType;
            Atom10FeedFormatter formatter = new Atom10FeedFormatter(_feed);
            formatter.WriteTo(xmlWriter);
        }
        else
        {
            response.ContentType = RssContentType;
            Rss20FeedFormatter formatter = new Rss20FeedFormatter(_feed);
            formatter.WriteTo(xmlWriter);
        }
        await xmlWriter.FlushAsync();
        content = stringWriter.ToString();
    }
    await response.WriteAsync(content);
}

Voilà ;)

Jérémy Jeanson

Comments

You have to be logged in to comment this post.