9

我有一个块的自定义实现,它的工作原理很像Html.BeginForm(). 实现基本如下:

public class MyBlock : IDisposable {
    private readonly HtmlHelper _html;

    public MyBlock(HtmlHelper hml) {
        this._html.ViewContext.Writer.WriteLine("BEGIN");
    }

    public void Dispose() {
        this._html.ViewContext.Writer.WriteLine("END");
    }
}

然后在我看来,我可以这样做:

@using (new MyBlock(Html)) {
    @: some content
}

要得到:

BEGIN
some content
END

这一切都很好。但是,当在“剃刀片段”中使用我的块时,我遇到了麻烦,例如,当将一些剃刀内容传递给以 aFunc<object, HelperResult>作为参数的函数时。例如,我有另一个 HtmlHelper 函数定义如下:

public static IHtmlString Content(this HtmlHelper @this, Func<object, HelperResult> razor) {
    return razor(null);
}

@* use in a view as: *@
@{
    var razorContent = Html.Content(@<div>Some razor content</div>);
}
@razorContent

但是,当我执行以下操作时,内部内容会在没有外部内容的情况下呈现:

@{ 
    var content =Html.Content(
        @<text>
            @using (new MyBlock(Html)) {
                @: some content 2
            }
        <text>
    );
}
@content

我认为问题在于“Html”仍然是指外部上下文的 HtmlHelper,因此 BEGIN 和 END 被发送到与“some content 2”不同的作者,但是,我不确定是否是这种情况。

有谁知道(1)出了什么问题以及(2)我该如何解决?

4

2 回答 2

2

您的问题的部分解决方案是调用 HelperResult 的 WriteTo 方法。您可以将 Content 方法更改为以下内容:

public static void Content(this HtmlHelper @this, Func<object, HelperResult> razor)
{
    razor(null).WriteTo(@this.ViewContext.Writer);
}

然后以这种方式使用它:

@{ Html.Content(
        @<text>
            @using (new MyBlock(Html)) {
                @: some content 2
            }
        </text>
    );
}

编辑

如果您想以 IHtmlString 或任何其他字符串的形式返回值,您可以这样做:

public static IHtmlString Content(this HtmlHelper @this, Func<object, HelperResult> razor)
{
    using (MemoryStream ms = new MemoryStream())
    using (TextWriter tw = new StreamWriter(ms))
    {
        Delegate @delegate = (Delegate)razor;
        WebViewPage target = (WebViewPage)@delegate.Target;
        TextWriter tmp = target.Html.ViewContext.Writer;
        try
        {
            target.Html.ViewContext.Writer = tw;
            razor(null).WriteTo(tw);
            tw.Flush();
            ms.Seek(0, SeekOrigin.Begin);
            TextReader tr = new StreamReader(ms);

            return MvcHtmlString.Create(tr.ReadToEnd());
        }
        finally
        {
            target.Html.ViewContext.Writer = tmp;
        }
    }
}
于 2013-01-10T19:34:31.990 回答
0

这也困扰了我一段时间。由于 MyBlock 和 HtmlHelper 使用不同的 Writer,这是一个剃刀错误。一个合理的解决方法是将 HtlmHelper 的 __razor_template_writer 传递给 MyBlock。(希望这将在 vnext 中修复)

public class MyBlock : IDisposable {
    private readonly TextWriter _writer;

    public MyBlock(TextWriter writer) {
        _writer = writer;
        _writer.WriteLine("BEGIN");
    }

    public void Dispose() {
        _writer.WriteLine("END");
    }
}

@{ 
    var content =Html.Content(
        @<text>
            @using (new MyBlock(__razor_template_writer)) {
                @: some content 2
            }
        <text>
    );
}
@content
于 2014-09-01T19:43:25.297 回答