Razor MVC 4 RC中第一行为空白行

8

我已经从MVC3迁移到MVC4,遇到了以下问题。

@using InvoiceDocflow.Controllers
@{
    Response.ContentType = "text/xml";
}
<?xml version="1.1" encoding="UTF-8" ?>
<dc>
    @foreach (var dcLink in (IEnumerable<DcLink>)ViewData["SupportedDcs"])
    {
        <link rel="@dcLink.RelUri.ToString()" href="@dcLink.DcUri.ToString()" />
    }
</dc>

这是我的视图。我的布局只有一行。
@RenderBody()

在MVC 3中,<?xml version="1.1" encoding="UTF-8" ?>出现在第一行,但现在它出现在第二行,导致第一行为空。我能否使其像MVC 3中那样呈现在第一行?
顺便说一下。
@using InvoiceDocflow.Controllers
@{
    Response.ContentType = "text/xml";
}<?xml version="1.1" encoding="UTF-8" ?>

这可以实现,但这不是我想要做的事情。

我在Mvc4的行为中没有看到任何bsd问题:它会将所有超出代码块的回车符复制到页面中,因此如果您不想要回车符,则必须将<?xml.....放在同一行上。这有什么问题吗? - Francesco Abbruzzese
我不需要代码块来隐式地影响输出。这是错误的。在MVC 3中还可以。 - er-v
重点是回车符号在代码块之外,因此会在输出中报告。虽然Vb是面向行的,但C#不是。显然,Mvc 4对代码块的定义与Mvc3不同...但我认为不能说Mvc 4的定义“是错误的”...只是不同而已。 - Francesco Abbruzzese
1
为什么不使用自定义操作结果来生成 XML 呢?在视图中手动创建 XML 而不是使用 XML 解析器非常危险。 - Darin Dimitrov
8个回答

7

当我尝试返回缓存清单文件时,遇到了类似于页面顶部空白行的问题。解决方案是,在页面的第一行添加Response.Write("...")。

 @{
     Layout = null;
     Response.Write("CACHE MANIFEST");

} .......

这个被低估的答案对我很有用。XML文件必须在第一行上具有doctype,没有任何前导空格。@{}部分将在页面上的任何其他内容之前执行。因此,Response.Write()也将在Razor添加页面内容前面的多余前导空格之前执行。将doctype移动到视图顶部,如其他一些答案所建议的那样,无法解决问题。 - Yogi

6

临时解决方案?使用ActionFilter并剥离空的第一行?如果适合的话,你也可以在响应中执行其他缩小操作。

public class TranslationFilter : MemoryStream
{
    private Stream filter = null;

    public TranslationFilter(HttpResponseBase httpResponseBase)
    {
        filter = httpResponseBase.Filter;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var response = UTF8Encoding.UTF8.GetString(buffer);

        // remove all newlines
        response = response.Replace(System.Environment.NewLine, "");

        /* remove just first empty line
          if (response.Substring(0, 2) == "\r\n")
        {
            response = response.Substring(2, response.Length - 2);
        } */

        filter.Write(UTF8Encoding.UTF8.GetBytes(response), offset, UTF8Encoding.UTF8.GetByteCount(response));
    }
}

public class ResponseFilter : ActionFilterAttribute
{
    public ResponseFilter()
    {
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        base.OnResultExecuted(filterContext);
        filterContext.HttpContext.Response.Filter = new TranslationFilter(filterContext.HttpContext.Response);
    }
}

并将其添加到控制器方法中?
[ResponseFilter]
public ActionResult Index()
{
return View();
}

这不是完整的解决方案。每个@{}块都会出现新行(不仅仅是第一个),因此我更喜欢能够处理它的解决方案。但是,如果没有其他选择,我将接受您的建议。 - er-v
已进行了调整以删除所有换行符,但显然这可能不是您想要的——这使得在浏览器中阅读HTML源代码更加困难。不过我很高兴能够提供帮助。 - Phil
这不是关于删除所有换行符。而是关于删除由@{}块引起的行。 - er-v
我相信错误在WhitespaceRewriter.cs或者RazorParser.cs这两个文件中。有人能发一下修复的pull request吗? - Annie

5

我知道这是一个老问题,但当我在寻找解决方案时,发现了它。

由于没有人提供简单的解决方案,所以我自己想出了一个:

我能够通过使用一个部分视图来修复这个问题。我认为问题归结于布局,即使你将其设置为 null,它仍然会添加一个空白的第一行。@{} 也会添加一个空白行,因此你必须将其移到视图底部。

所以只需添加一个部分视图,并让控制器返回该部分视图,如下所示:

public ActionResult GenerateXML()
{
    return PartialView("_XML");
}

然后在你的部分视图中,你需要按照这样的方式设置它(在底部使用@{}):

@model string
<?xml version="1.0" encoding="UTF-8" ?>
<response>
    <message>@Model</message>
</response>
@{ Response.ContentType = "text/xml";}

这将导致生成以下HTML源代码:
<?xml version="1.0" encoding="UTF-8" ?>
<response>
    <message>Response Message</message>
</response>

我希望这能帮助遇到此问题的其他人。

2

“解决方案2”非常好用(我正在生成缓存清单文件)。感谢分享! - Anthony Chu
evanswd 在评论中提出的建议对我很有帮助,而且非常简单易懂! - Avrohom Yisroel
1
请在答案中提供解决方案的内联摘要,或将此链接转换为评论。 - Alexei Levenkov

2

我知道你建议将标签移动到@{}的末尾,但为什么不把它放在那之前呢?此外,这个空格是否会导致错误或问题?可以清楚地看到,这是由你的代码创建的空格,而不是来自mvc或razor。

也许像这样:

@using InvoiceDocflow.Controllers
<?xml version="1.1" encoding="UTF-8" ?>
@{
 Response.ContentType = "text/xml";
}

2
我是这样解决类似问题的:

_ViewStart.cshtml

@{
    Layout = null;
    Response.Write("<!DOCTYPE html>");
}

另一个 .cshtml

@model ViewModel<EshopWebsiteOrder>
<html>
<head>
    <meta charset="utf-8" />

最后,在一个地方定义通用的 DOCTYPE 是有意义的。

1

还有一种简单的解决方法,可以不使用ResponseFilter。只需将@using放在cshtml文件底部即可:

<?xml version="1.1" encoding="UTF-8" ?>
<dc>
    @foreach (var dcLink in (IEnumerable<DcLink>)ViewData["SupportedDcs"])
    {
        <link rel="@dcLink.RelUri.ToString()" href="@dcLink.DcUri.ToString()" />
    }
</dc>
@using InvoiceDocflow.Controllers
@{
    Response.ContentType = "text/xml";
}

1
如果您移动:

<?xml version="1.1" encoding="UTF-8" ?>

将Layout模板的顶部插入,然后让您的xml页面继承它并输出您的xml数据,应该可以工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接