好的,我正在和ILSpy一起巡游并试图弄清楚这里发生了什么,但我没有太多运气。
在ASP.NET MVC4应用程序的给定视图中(,当然这适用于MVC3,可能是2 )使用Razor引擎,OutputStack
属性继承自{{ 3}}只是一堆WebPageBase
个对象。
通过从该堆栈推送和弹出,可以操纵给定Razor视图的输出。我希望利用HTML帮助扩展方法来利用它,但我也注意到TextWriter
,它也是ViewContext
的公共成员它自己的TextWriter 。
现在,我进行了快速检查:(来自视图)
@object.ReferenceEquals(this.ViewContext.Writer, this.OutputStack.Peek()) // True
但是,以下让我感到困惑:
@{
// push one on
OutputStack.Push(new StringWriter());
}
Hello!
@{
// capture everything and pop it
string buffer1 = OutputStack.Peek().ToString();
OutputStack.Pop();
}
<pre>@(buffer1)</pre>
@{
// apparently it references the top of the OutputStack
// so this should be essentially the same
var oldWriter = ViewContext.Writer;
ViewContext.Writer = new StringWriter();
}
World!
@{
// revert it and hope for the best
string buffer2 = ViewContext.Writer.ToString();
ViewContext.Writer = oldWriter;
}
<pre>@(buffer2)</pre>
以上结果如下:
Hello!
被捕获到buffer1
,并在<pre>Hello!</pre>
之后被转储。这既是预期的,也是期望的。World!
立即输出,然后是空<pre></pre>
块;换句话说,它没有捕获任何东西。我的问题如下:这些TextWriter
个对象如何相互关联,为什么我无法通过ViewContext
管理OutputStack
的引用。{{1} }}? (相当,如何我可以通过ViewContext
管理引用吗?)
附录
我遇到过的详细信息和其他废话。
Writer
的{{1}}属性不会丢弃传递给setter的值,因此在第二个示例的情况下,不只是丢弃它。ViewContext
实际上来自HtmlHelper
。OutputStack
使用ViewContext.Writer
属性WebViewPage.ExecutePageHierarchy()
,{em>这是WebViewPage
的顶部,在Output
中设置了! (只是我,或者这开始看起来像是老鼠的依赖巢?)答案 0 :(得分:2)
我发表评论作为答案。它可能会注意到解决问题的学术部分,但它肯定可以解决问题的实际部分,最重要的是解决您试图解决的最初问题。
在您的助手中,您可以获得当前视图的OutputStack
:
public static void MyHelper(this HtmlHelper html)
{
var stack = ((WebPageBase)html.ViewDataContainer).OutputStack;
... you could push and pop here and solve your real world problem
}
答案 1 :(得分:1)
根据我上面的评论,您似乎需要手动保持OutputStack.Peek()和ViewContext.Writer同步。以下辅助方法将执行此操作:
private class WriterScope : IDisposable
{
private HtmlHelper _html;
private TextWriter _previous;
public WriterScope(HtmlHelper html, TextWriter writer)
{
_html = html;
_previous = _html.ViewContext.Writer;
_html.ViewContext.Writer = writer;
((WebPageBase)_html.ViewDataContainer).OutputStack.Push(writer);
}
public void Dispose()
{
var stack = ((WebPageBase) _html.ViewDataContainer).OutputStack;
if (stack.Peek() == _html.ViewContext.Writer)
_html.ViewContext.Writer = _previous;
stack.Pop();
_html = null;
_previous = null;
}
}
public static IDisposable Scope(this HtmlHelper html, TextWriter writer)
{
return new WriterScope(html, writer);
}
在视图中,它可以像这样使用:
@{
var sw = new StringWriter();
using (Html.Scope(sw))
{
<p>Line 2</p>
<p>@Html.Raw("Line 3")</p>
<p>Line 4</p>
}
}
<p>Line 1</p>
@Html.Raw(sw.ToString())
页面按预期输出以下内容:
Line 1
Line 2
Line 3
Line 4