2012-04-04 19 views
8

Estoy intentando escribir un asistente html de estilo BeginForm que usa IDisposable para ajustar otro código. Quiero que el ayudante solo represente el código ajustado si se cumple una determinada condición (por ejemplo, el usuario cumple una determinada función).Captura de contenido envuelto en ayudante html desechable del estilo BeginForm

Pensé que podría simplemente cambiar el contexto. Escriba en el método Begin y vuelva a cambiarlo en el método Dispose. El siguiente código compila y ejecuta, pero el contenido envuelto se procesa en todos los casos. Si lo paso, el contenido envuelto no se escribe en el nuevo StringWriter y, por lo tanto, no está bajo mi control.

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

¿Es lo que estoy tratando de hacer posible con html helpers?

Sé que los ayudantes html declarativos en la maquinilla de afeitar probablemente funcionarían, pero preferirían el enfoque html helper estándar si fuera posible, dada la limitación de app_code de los maquinillas de afeitar en MVC3.

Respuesta

6

No se puede representar condicionalmente el contenido del cuerpo de un método auxiliar que devuelve IDisposable. Siempre rendirá. Puede usar este estilo de ayudantes cuando desee envolver el cuerpo del bloque using con algún marcador personalizado como el BeginForm que el ayudante hace con el elemento <form>.

Se puede usar un templated Razor delegate lugar:

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

y luego:

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

En realidad se puede condicionalmente ocultar el contenido con una estructura similar a BeginForm. Sólo implica jugar con el StringBuilder interna un poco:

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

continuación, sólo tiene que hacer un HtmlHelper que hace que una instancia del objeto por encima de

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

uso es el siguiente:

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

Ventajas:

  • Escriba la lógica personalizada para mostrar/ocultar su contenido y pasarlo al constructor Restringido.
  • propiedades públicas en su objeto restringido son accesibles en el bloque de código en su vista, por lo que puede reutilizar los valores calculados allí.

Probado con ASP.Net MVC 4

+0

Usted debe comentar de salida el código "allowcontent", simplemente no hacer nada allí. De lo contrario, obtengo contenido anidado. Además, la copia de seguridad solo es necesaria cuando Allowed es 'falso' – Alex

+0

Gracias @jitbit, actualicé mi publicación. Solo una idea de último momento, por cierto: esta clase Secured agrega muy poco valor sobre declaraciones if simples incorporadas ... Solo tomaría esta ruta si necesitas manipular el HTML, y he probado todas las otras opciones. He trabajado mucho con Razor desde que hice esta publicación y encuentro que la sintaxis de "usar" en Razor ve el abuso del lenguaje en lugar de la sintaxis del azúcar. – Moeri

Cuestiones relacionadas