使用HtmlHelper来消费html/text
本文关键字:html text HtmlHelper 使用 | 更新日期: 2023-09-27 18:04:32
我正在尝试制作一个HTML帮助器,允许使用内的任何文本被消耗,而不是写入最终页面。
剃刀:
<div>
<p>
Before Inline
</p>
@using (Html.IncludeInlineScript("testScript"))
{
<script type="text/javascript">
alert("hello world");
</script>
}
<p>
After Inline
</p>
</div>
生成的HTML:
<div>
<p>
Before Inline
</p>
<script type="text/javascript">
alert("hello world");
</script>
<!-- Top of Dispose -->
<!-- Bottom of Dispose -->
<p>
After Inline
</p>
</div>
Helper扩展方法:
public static ScriptWrapper IncludeInlineScript(this HtmlHelper helper, string scriptName)
{
return new ScriptWrapper(helper);
}
包装:
public class ScriptWrapper : IDisposable
{
private HtmlHelper _helper;
private TextWriter _originalWriter;
private StringBuilder _scriptContents;
public ScriptWrapper(HtmlHelper helper)
{
_helper = helper;
_originalWriter = _helper.ViewContext.Writer;
_scriptContents = new StringBuilder();
_helper.ViewContext.Writer = new StringWriter(_scriptContents);
}
public void Dispose()
{
_originalWriter.WriteLine("<!-- Top of Dispose -->");
_helper.ViewContext.Writer.Flush();
_helper.ViewContext.Writer = _originalWriter;
_originalWriter.WriteLine("<!-- Bottom of Dispose -->");
}
}
这里的问题是,尽管将ViewContext.Writer
设置为一个新的TextWriter,它仍然是写到原来的writer。显然,调用dispose的顺序是正确的,因为dispose的顶部位于脚本之后。在设置了新的写入器后进行调试时,<script>
块不在流中,但是在处理时,<script>
现在包含在原始写入器中。
razor引擎是否保留了写入器的本地副本,并忽略了它已被设置为不同实例的事实?
如果有人想要解决这个问题,因为我很不耐烦,我找到了一个方法来完成这个工作。虽然不太理想,但还是管用的。如果将ScriptWrapper
修改为:
public class ScriptWrapper : IDisposable
{
private HtmlHelper _helper;
private string _originalString;
private StringBuilder _sb;
public ScriptWrapper(HtmlHelper helper)
{
_helper = helper;
_sb = ((StringWriter) _helper.ViewContext.Writer).GetStringBuilder();
_originalString = _sb.ToString();
_sb.Clear();
}
public void Dispose()
{
var contents = _sb.ToString();
_sb.Clear();
_sb.Append(_originalString);
}
}
您可以在using(...)
语句中使用任何内容,从而实现所需的结果。
我仍然很想知道是否有一种方法可以做到这一点,而不用像这样破解解决方案
在您的原始(问题)中,很容易认为因为标记在using块中,所以ScriptWrapper以某种方式正在使用标记
<script type="text/javascript">
alert("hello world");
</script>
,但正如你所发现的,它是不是被ScriptWrapper
以任何方式消耗。您希望此标记将被"重定向"到其他地方,即您创建的编写器,但事实并非如此。相反,您创建的写入器也用于写入响应流,这就是ViewContext.Writer
的用途,无论它恰好是什么写入器。
因此,Razor并没有让ScriptWrapper消费标记,而是将其解释为视图中的其他标记,并在解释后将其写入响应流。从Razor的角度来看,标记是用于输出的,而不是用于ScriptWrapper。只是将它包含在using块中,并不会使标记减少整体视图的一部分。
您回答成功,因为您没有将标记重定向到其他地方(这不起作用),而是因为您正在编辑最终在响应流中的内容,从而有效地从响应流中删除标记。
我认为你的解决方案不是一个hack,而是一个正确的方法,考虑到你想要完成的任务。