2012-04-04 19 views
8

Próbuję napisać pomocnika HTML stylu BeginForm, który używa IDisposable do owinięcia innego kodu. Chcę, aby pomocnik renderował zawijany kod tylko wtedy, gdy spełniony jest określony warunek (np. Użytkownik jest w określonej roli).Przechwyć zapakowaną zawartość w stylu BeginForm w stylu pomocnika html

Pomyślałem, że mogę po prostu zmienić kontekst.Wersja w metodzie Rozpocznij i przełącz ją z powrotem w metodzie Usuwanie. Poniższy kod jest kompilowany i uruchamiany, ale zawijana treść jest renderowana we wszystkich przypadkach. Jeśli przejdę przez to, zawinięte treści nie zostaną zapisane w nowym StringWriter, a zatem nie będą podlegały mojej kontroli.

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

Czy to, co próbuję zrobić z pomocą html?

Wiem, że deklaratywni pomocnicy html w maszynce do golenia prawdopodobnie by działali, ale woleliby, jeśli to możliwe, standardowy html helper, biorąc pod uwagę ograniczenie app_code pomocników maszynki do golenia w MVC3.

Odpowiedz

6

Nie można warunkowo zrenderować zawartości treści metody pomocniczej zwracającej IDisposable. Zawsze będzie renderować. Możesz użyć tego stylu pomocników, gdy chcesz owinąć bryłę bloku using za pomocą niestandardowego znacznika, takiego jak pomocnik BeginForm z elementem .

można użyć templated Razor delegate zamiast:

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

a następnie:

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

Właściwie można warunkowo ukryć zawartość z BeginForm-podobnej strukturze. To tylko polega brudząc z wewnętrznym StringBuilder trochę:

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

Następnie wystarczy dokonać HtmlHelper sprawia, że ​​wystąpienie powyższego obiektu

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

użycia jest następujący:

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

Zalety:

  • Napisz niestandardową logikę, aby pokazać/ukryć swoją zawartość i przekazać ją do konstruktora Ograniczony.
  • właściwości publiczne w Twoim obiekcie z ograniczeniami są dostępne w bloku kodu w widoku, więc możesz tam ponownie użyć obliczonych wartości.

Testowane z ASP.NET MVC 4

+0

Należy skomentować wymeldowania się "allowcontent" kodu, po prostu nic nie robić. W przeciwnym razie dostanę zawartość zagnieżdżoną. Kopie zapasowe są potrzebne tylko wtedy, gdy Dozwolone jest "false" – Alex

+0

Dzięki @jitbit, zaktualizowałem swój wpis. Pomyślnie przy okazji: ta klasa Secured dodaje niewiele wartości w porównaniu z prostymi wbudowanymi instrukcjami if ... Mogę wziąć tę trasę tylko wtedy, gdy trzeba manipulować kodem HTML i wypróbować wszystkie inne opcje. Pracowałem z maszynką Razor, odkąd napisałem ten post, i znajduję składnię "używania" w artykule Razor, a nie syntaktycznego cukru. – Moeri