捕获BeginForm样式的一次性html帮助程序中的包装内容

Pau*_*les 9 html-helper asp.net-mvc-3

我正在尝试编写一个BeginForm样式的html帮助器,它使用IDisposable来包装其他代码.我希望帮助器只在满足某个条件时呈现包装的代码(例如,用户处于某个角色).

我以为我可以简单地在Begin方法中切换context.Writer并在Dispose方法中将其切换回来.下面的代码编译并运行,但包装的内容在所有情况下都会呈现.如果我单步执行它,包装的内容不会写入新的StringWriter,因此不在我的控制范围内.

    public static IDisposable BeginSecure(this HtmlHelper html, ...)
    {
        return new SecureSection(html.ViewContext, ...);
    }

    private class SecureSection : IDisposable
    {
        private readonly ViewContext _context;
        private readonly TextWriter _writer;

        public SecureSection(ViewContext context, ...)
        {
            _context = context;
            _writer = context.Writer;
            context.Writer = new StringWriter();
        }

        public void Dispose()
        {
            if (condition here)
            {
                _writer.Write(_context.Writer);
            }

            _context.Writer = _writer;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我正在尝试用html帮助器做什么?

我知道razor中的声明性html助手可能会工作,但如果可能的话,我会更喜欢标准的html助手方法,因为MVC3中的razor助手的app_code限制.

Moe*_*eri 10

实际上,您可以使用类似BeginForm的结构有条件地隐藏内容.它只涉及到内部StringBuilder的乱码:

public class Restricted: IDisposable
{
    public bool Allow { get; set; }

    private StringBuilder _stringBuilderBackup;
    private StringBuilder _stringBuilder;
    private readonly HtmlHelper _htmlHelper;

    /// <summary>
    /// Initializes a new instance of the <see cref="Restricted"/> class.
    /// </summary>
    public Restricted(HtmlHelper htmlHelper, bool allow)
    {
        Allow = allow;
        _htmlHelper = htmlHelper;
        if(!allow) BackupCurrentContent();
    }

    private void BackupCurrentContent()
    {
        // make backup of current buffered content
        _stringBuilder = ((StringWriter)_htmlHelper.ViewContext.Writer).GetStringBuilder();
        _stringBuilderBackup = new StringBuilder().Append(_stringBuilder);
    }

    private void DenyContent()
    {
        // restore buffered content backup (destroying any buffered content since Restricted object initialization)
        _stringBuilder.Length = 0;
        _stringBuilder.Append(_stringBuilderBackup);
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        if(!Allow)
            DenyContent();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你只需要创建一个HtmlHelper来创建上述对象的实例

public static class RestrictedHelper
{
    public static Restricted RestrictedContent(this HtmlHelper htmlHelper, bool allow)
    {
        return new Restricted(htmlHelper, allow);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

@using (var restricted = Html.Restricted(true))
{
    <p>This will show up</p>
}
@using (var restricted = Html.Restricted(false))
{
    <p>This won't</p>
}
Run Code Online (Sandbox Code Playgroud)

好处:

  • 编写自定义逻辑以显示/隐藏您的内容并将其传递给Restricted构造函数.
  • 您在Restricted对象中的公共属性可以在视图中的代码块中访问,因此您可以在那里重用计算值.

用ASP.Net MVC 4测试


Dar*_*rov 6

您无法有条件地渲染辅助方法返回的正文内容IDisposable.它将始终呈现.当你想using用一些自定义标记包装块的主体时,你可以使用这种类型的帮助器,例如BeginForm帮助器与<form>元素一起使用.

你可以用一个templated Razor delegate代替:

public static class HtmlExtensions
{
    public static HelperResult Secure(this HtmlHelper html, Func<object, HelperResult> template)
    {
        return new HelperResult(writer =>
        {
            if (condition here)
            {
                template(null).WriteTo(writer);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

@Html.Secure(
    @<div>
         You will see this text only if some condition is met
    </div>
)
Run Code Online (Sandbox Code Playgroud)