Asp.net-Mvc-3

在 BeginForm 樣式的一次性 html 助手中擷取包裝的內容

  • December 17, 2014

我正在嘗試編寫一個 BeginForm 樣式的 html 助手,它使用 IDisposable 來包裝其他程式碼。我希望助手僅在滿足特定條件時才呈現包裝程式碼(例如,使用者處於特定角色)。

我認為我可以簡單地在 Begin 方法中切換 context.Writer 並在 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 助手做的事情嗎?

我知道 razor 中的聲明性 html 助手可能會起作用,但如果可能的話,我會更喜歡標準的 html 助手方法,因為 MVC3 中 razor 助手的 app_code 限制。

您不能有條件地呈現輔助方法返回的主體內容IDisposable。它會一直渲染。當你想using用一些自定義標記包裝塊的主體時,你可以使用這種風格的助手,比如BeginForm助手對<form>元素所做的。

您可以使用 atemplated 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>
)

實際上**,您可以**使用類似 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>
}

好處:

  • 編寫自定義邏輯以顯示/隱藏您的內容並將其傳遞給 Restricted 建構子。
  • Restricted 對像中的公共屬性可以在視圖中的程式碼塊中訪問,因此您可以在那裡重用計算值。

用 ASP.Net MVC 4 測試

引用自:https://stackoverflow.com/questions/10013095