8

Вопрос по html-helper, asp.net-mvc-3 – Захват обернутого содержимого в одноразовом html-помощнике в стиле BeginForm

Я пытаюсь написать помощник в стиле BeginForm, который использует IDisposable для переноса другого кода. Я хочу, чтобы помощник отображал свернутый код только при соблюдении определенного условия (например, пользователь находится в определенной роли).

Я подумал, что могу просто переключить context.Writer в методе Begin и переключить его обратно в метод 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;
        }
    }

Возможно ли то, что я пытаюсь сделать с помощью помощников HTML?

Я знаю, что декларативные html-помощники в razor, вероятно, будут работать, но, если возможно, предпочтут стандартный html-помощник, учитывая ограничение app_code для razor-помощников в MVC3.

2 ответа
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);
            }
        });
    }
}

а потом:

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

На самом деле

you can условно скрыть контент с 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();
    }
}

Тогда вам просто нужно сделать HtmlHelper, который делает экземпляр вышеупомянутого объекта

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

Использование заключается в следующем:

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

Преимущества:

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.

Протестировано с ASP.Net MVC 4

Спасибо @jitbit, я обновил свой пост. Кстати, просто запоздалая мысль: этот класс Secured добавляет очень мало значения к простым встроенным операторам if ... Я бы пошел по этому пути, только если вам нужно манипулировать HTML, и попробовал все другие варианты. Я много работал с Razor с тех пор, как написал этот пост, и обнаружил, что "использую" Синтаксис в Razor рассматривает злоупотребление языком, а не синтаксический сахар.

от 

Вы должны закомментировать & quot; allowcontent & quot; код, просто ничего не делай там. В противном случае я получаю вложенный контент. Кроме того, резервное копирование необходимо только тогда, когда разрешеноfalse

от 

Похожие вопросы