Capture wrapped content in BeginForm style disposable html helper

别说谁变了你拦得住时间么 提交于 2019-11-28 12:13:45

You can't conditionally render the body contents of a helper method returning IDisposable. It will always render. You could use this style of helpers when you want to wrap the body of the using block with some custom markup such as the BeginForm helper does with the <form> element.

You could use a templated Razor delegate instead:

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);
            }
        });
    }
}

and then:

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

Actually you can conditionally hide content with a BeginForm-like structure. It only involves messing with the internal StringBuilder a bit:

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();
    }
}

Then you just need to make an HtmlHelper that makes an instance of the above object

public static class RestrictedHelper
{
    public static Restricted RestrictedContent(this HtmlHelper htmlHelper, bool allow)
    {
        return new Restricted(htmlHelper, allow);
    }
}

Usage is as follows:

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

Advantages:

  • Write custom logic to show/hide your content and pass it to the Restricted constructor.
  • public properties in your Restricted object are accessible in the block of code in your view, so you can reuse calculated values there.

Tested with ASP.Net MVC 4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!