2012-04-04 12 views
8

Sto cercando di scrivere un helper html in stile BeginForm che utilizza IDisposable per avvolgere altro codice. Voglio che l'helper esegua il rendering del codice spostato solo se viene soddisfatta una determinata condizione (ad esempio, l'utente si trova in un determinato ruolo).Catturare contenuto avvolto in helper html monouso in stile BeginForm

Ho pensato che avrei potuto semplicemente cambiare il contesto. Scrittura nel metodo Begin e reinserirlo nel metodo Dispose. Il codice seguente viene compilato ed eseguito ma il contenuto avvolto viene sottoposto a rendering in tutti i casi. Se lo passo, il contenuto avvolto non viene scritto nel nuovo StringWriter e quindi non è sotto il mio controllo.

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

È ciò che sto cercando di fare con gli helper html?

So che gli helper dichiarativi html nel rasoio funzionerebbero probabilmente, ma preferirebbero un approccio helper standard html se possibile, data la limitazione app_code degli helper del rasoio in MVC3.

risposta

6

Non è possibile eseguire il rendering condizionale del contenuto del corpo di un metodo di supporto che restituisce IDisposable. Renderà sempre. È possibile utilizzare questo tipo di helper quando si desidera avvolgere il corpo del blocco using con alcuni markup personalizzati come l'helper BeginForm con l'elemento <form>.

si potrebbe usare un templated Razor delegate invece:

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

e poi:

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

realtà si può condizionalmente nascondere il contenuto con una struttura BeginForm-like. E 'solo comporta scherzi con lo StringBuilder interna un po':

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

Poi basta fare un HtmlHelper che rende un'istanza di tale scopo si

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

uso è il seguente:

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

Vantaggi:

  • Scrivere la logica personalizzata per mostrare/nascondere il contenuto e passarlo al costruttore Limitato.
  • Le proprietà pubbliche nell'oggetto con restrizioni sono accessibili nel blocco di codice nella visualizzazione, quindi è possibile riutilizzare i valori calcolati lì.

Testato con ASP.Net MVC 4

+0

si dovrebbero commentare-out il codice "allowcontent", semplicemente non fare nulla lì. Altrimenti ricevo contenuto annidato. Inoltre, il backup è necessario solo quando Consentito è 'falso' – Alex

+0

Grazie @jitbit, ho aggiornato il mio post. A proposito: questa classe Secured aggiunge molto poco valore alle semplici istruzioni if ​​incorporate ... Prenderò questa rotta solo se hai bisogno di manipolare l'HTML e ho provato tutte le altre opzioni. Ho lavorato molto con Razor da quando ho creato questo post, e ho trovato la sintassi "using" in Razor per quanto riguarda l'abuso del linguaggio piuttosto che lo zucchero della sintassi. – Moeri

Problemi correlati