문제

어제 MVC 4로 업그레이드했는데 업그레이드로 인해 발생한 버그를 발견했습니다.

RSS 피드를 생성하는 데 사용되는 Razor 뷰가 있습니다.여기에는 다음과 같은 마크업이 있습니다(단순화).

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

Razor 버전 2에는 다음이 있습니다. 특별 지원 ~을 위한 HTML5 무효 요소.이러한 보이드 요소는 자동으로 닫히며 닫는 태그가 없습니다.

안타깝게도, <link> 그러한 요소 중 하나입니다.

이는 위의 Razor 마크업이 더 이상 유효하지 않으며 런타임 시 실패함을 의미합니다.마감 제거 </link> 태그는 파서 오류를 제거하지만 더 이상 유효한 RSS가 아님을 의미합니다.

그렇다면 이 문제를 해결할 수 있는 방법이 있습니까? 아니면 Razor가 실제로 HTML5 생성에만 적합합니까?

도움이 되었습니까?

해결책 4

이 질문에 대한 짧은 대답은 Razor가 버전 2와 마찬가지로 XML을 제외하고 HTML에 묶여 있다는 것입니다.나 개발자 중 한 명에게 확인을 요청했습니다., 그래서 그가 돌아오길 바랍니다.

결국 Linq를 XML로 사용하고 사용자 정의 방법을 변경했습니다. ActionResult, Razor 및 실제로 모든 뷰 엔진을 우회합니다.

[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;
}

이를 위해서는 다음과 같은 사용자 정의가 필요합니다 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);
    }
}

다른 팁

이렇게 할 것입니다 :

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

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

생성 된 소스는 다음과 같습니다.

<item>
    <title>
        Google
    </title>

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

지금이 해결 방법으로 이동합니다.

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

Alexander Taran이 이에 대한 확실한 답을 찾기 위해 이 질문에 현상금을 걸었기 때문에 다음을 확인해 봐야겠다고 생각했습니다. CodePlex의 Razor 소스 코드 세부정보를 제공하세요.

먼저 다음을 살펴보세요. HtmlMarkupParser.여기에는 다음 참조 데이터가 포함되어 있습니다.

//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"
};

이는 다음을 통해 노출됩니다. HtmlMarkupParser.VoidElements, 이며 이 속성의 유일한 사용법은 다음과 같습니다. HtmlMarkupParser.RestOfTag(...).이것은 일련의 토큰을 탐색하는 파서입니다.관련 코드 조각은 다음과 같습니다.

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();
}

이는 다음이 성공적으로 구문 분석됨을 의미합니다.

<link></link>

그러나 미리보기는 제한되어 있습니다. 즉, 닫는 태그 앞에 추가 토큰이 표시되면 실패하게 됩니다.

<link>Some other tokens</link>

이 경우 미리보기 범위를 확장하는 것이 가능할 수 있습니다.누구든지 관심이 있다면 MVC 팀에 끌어오기 요청을 제공할 수 있습니다.

HTML5 링크는 스타일 시트 등의 헤더에서 사용되는 특수 요소입니다.

RSS는 HTML5가 아니라

와 같은 것입니다.
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
.

RSS 피드가

를 사용하는 레이아웃 컨트롤러 에서이 작업을 가질 수 있습니다.
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
    @RenderBody()
</rss>
.

필자가 해왔 던 대체 방법은 완전히 빈보기를 완전히 비워두고 아래의 컨트롤러를 가지고있는 것입니다.

    [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);
    }
.

특히 System.ServiceModel.Syndication.SyndicationFeed

그리고 이것은 내 사용자 정의 결과

입니다.
 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);
            }
        }
    }
.

할 수있는 일은 다음과 같습니다.

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

훨씬 간단합니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top