Pregunta

He actualizado a MVC 4 ayer y acabo de descubrir un error por el que la actualización introducida.

Tengo una maquinilla de Afeitar de vista que se utiliza para generar un feed RSS.Tiene algunas marcado como esta (simplificado):

<item>
    <title>@post.BlogPost.Title</title> 
    <link>@Url.BlogPost(post.BlogPost, isAbsolute: true)</link>
</item>

En la maquinilla de Afeitar de la versión dos, hay apoyo especial para HTML5 void elementos.Tal nulidad elementos de cierre automático, y no tienen una etiqueta de cierre.

Por desgracia, <link> es uno de esos elementos.

Esto significa que por encima de la maquinilla de Afeitar de marcado no es válida, y se produce un error en tiempo de ejecución.La eliminación de la clausura </link> etiqueta elimina el error del analizador, pero significa que ya no es válido RSS.

Así que, ¿hay una manera de conseguir alrededor de esto, o es maquinilla de Afeitar realmente sólo adecuado para la generación de HTML5?

¿Fue útil?

Solución 4

La respuesta corta a esta pregunta, parece ser que la maquinilla de Afeitar, como a través de la versión 2, está ligada a HTML para la exclusión de XML.Yo pregunté a uno de los dev de la confirmación, así que espero que vuelva.

Terminé de cambiar mi método de usar Linq to XML, y es una costumbre ActionResult, evitando de Afeitar y, de hecho, cualquier motor de vista:

[HttpGet]
[OutputCache(Duration = 300)]
public ActionResult Feed()
{
    var result = new XmlActionResult(
        new XDocument(
            new XElement("rss",
                new XAttribute("version", "2.0"),
                new XElement("channel",
                    new XElement("title", "My Blog")
                    // snip
                )
            )
        )
    );

    result.MimeType = "application/rss+xml";

    return result;
}

Esto requiere el siguiente personalizado ActionResult:

public sealed class XmlActionResult : ActionResult
{
    private readonly XDocument _document;

    public Formatting Formatting { get; set; }
    public string MimeType { get; set; }

    public XmlActionResult([NotNull] XDocument document)
    {
        if (document == null)
            throw new ArgumentNullException("document");

        _document = document;

        // Default values
        MimeType = "text/xml";
        Formatting = Formatting.None;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.Clear();
        context.HttpContext.Response.ContentType = MimeType;

        using (var writer = new XmlTextWriter(context.HttpContext.Response.OutputStream, Encoding.UTF8) { Formatting = Formatting })
            _document.WriteTo(writer);
    }
}

Otros consejos

Yo lo haría así:

<item>
   <title>
      @post.BlogPost.Title
   </title>

   @Html.Raw("<link>")
      @Url.BlogPost(post.BlogPost, isAbsolute: true)
   @Html.Raw("</link>")
</item>

Fuente generado tendrá este aspecto:

<item>
    <title>
        Google
    </title>

     <link>
         http://www.google.se
    </link>
</item>

Por ahora voy con esta solución:

 @Html.Raw(string.Format(@"<param name=""{0}"">{1}</param>",Name, Value)) 

Desde que Alexander Taran ha abierto una recompensa en esta pregunta en una búsqueda de una respuesta definitiva a esto, pensé en retirar el Maquinilla de afeitar de código fuente en CodePlex y proporcionar algunos detalles.

En primer lugar, echar un vistazo a HtmlMarkupParser.Contiene esta referencia de los datos:

//From http://dev.w3.org/html5/spec/Overview.html#elements-0
private ISet<string> _voidElements = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen",
    "link", "meta", "param", "source", "track", "wbr"
};

Este es expuesto a través de HtmlMarkupParser.VoidElements, y el único uso de esta propiedad es en HtmlMarkupParser.RestOfTag(...).Este es un analizador que caminar a través de una secuencia de tokens.El correspondiente fragmento de código es:

if (VoidElements.Contains(tagName))
{
    // Technically, void elements like "meta" are not allowed to have end tags. Just in case they do,
    // we need to look ahead at the next set of tokens. If we see "<", "/", tag name, accept it and the ">" following it
    // Place a bookmark
    int bookmark = CurrentLocation.AbsoluteIndex;

    // Skip whitespace
    IEnumerable<HtmlSymbol> ws = ReadWhile(IsSpacingToken(includeNewLines: true));

    // Open Angle
    if (At(HtmlSymbolType.OpenAngle) && NextIs(HtmlSymbolType.Solidus))
    {
        HtmlSymbol openAngle = CurrentSymbol;
        NextToken();
        Assert(HtmlSymbolType.Solidus);
        HtmlSymbol solidus = CurrentSymbol;
        NextToken();
        if (At(HtmlSymbolType.Text) && String.Equals(CurrentSymbol.Content, tagName, StringComparison.OrdinalIgnoreCase))
        {
            // Accept up to here
            Accept(ws);
            Accept(openAngle);
            Accept(solidus);
            AcceptAndMoveNext();

            // Accept to '>', '<' or EOF
            AcceptUntil(HtmlSymbolType.CloseAngle, HtmlSymbolType.OpenAngle);
            // Accept the '>' if we saw it. And if we do see it, we're complete
            return Optional(HtmlSymbolType.CloseAngle);
        } // At(HtmlSymbolType.Text) && String.Equals(CurrentSymbol.Content, tagName, StringComparison.OrdinalIgnoreCase)
    } // At(HtmlSymbolType.OpenAngle) && NextIs(HtmlSymbolType.Solidus)

    // Go back to the bookmark and just finish this tag at the close angle
    Context.Source.Position = bookmark;
    NextToken();
}

Esto significa que el siguiente será analizar correctamente:

<link></link>

Sin embargo, el lookahead es limitada, lo que significa que cualquier extra tokens visto antes de la etiqueta de cierre de hacer fallar:

<link>Some other tokens</link>

Es posible extender el alcance de la oteo en este caso.Si alguien está interesado, que puede proporcionar un pull request para el MVC equipo.

Html5 enlace es un elemento especial se utiliza en el encabezado de las hojas de estilo y el gusto.

Tu Rss no debe ser Html5, pero algo como

<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">

usted podría tener esto en un diseño de controlador de tus feeds rss usaría

<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
    @RenderBody()
</rss>

Una forma alternativa en que lo he hecho previosly es de tener una vista vacía y, a continuación, el controlador de abajo:

    [NHibernateActionFilter]
    public AtomActionResult Feed()
    {
        var dto = _service.GetThings(NHibernateSession);
        var items = Mapper.Map<List<ThingDto>, List<SyndicationItem>>(dto);
        var url = HttpContextWrapper.Request.UrlReferrer;
        var feed = new SyndicationFeed("MyTitle", "MyByline", url, items)
        {
            Copyright = new TextSyndicationContent("© 2012 SO"),
            Language = "en-IE"
        };
        return new AtomActionResult(feed);
    }

De la nota particular es System.ServiceModel.Syndication.SyndicationFeed

Y este es mi resultado personalizadas

 public class AtomActionResult : ActionResult
    {
        readonly SyndicationFeed _feed;

        public AtomActionResult() { }

        public AtomActionResult(SyndicationFeed feed)
        {
            _feed = feed;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            //context.HttpContext.Response.ContentType = "application/atom+xml";
            //chrome does not yet support atom+xml 
            //http://code.google.com/p/chromium/issues/detail?id=104358
            context.HttpContext.Response.ContentType = "application/xml";
            var formatter = new Atom10FeedFormatter(_feed);
            using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output))
            {
                formatter.WriteTo(writer);
            }
        }
    }

Lo que puedes hacer es esto:

@("<link>" + Url.BlogPost(post.BlogPost, isAbsolute: true) + "</link>")

mucho más simple

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top