The asp.Net MVC framework is a wonderful addition to the asp.Net technology set. Microsoft was one of the last developer tool sets to provide an MVC framework, but Microsoft’s implementation of MVC is easier to implement and understand than most. One of the key features of the MVC framework is the use of strongly typed view data to build the display view. The view file is only concerned with displaying the data provided by the controller. This strategy reduces the risk of business logic creeping into the view, helps enforce separation of concerns, and typically makes for cleaner Html delivered to the browser.
One to the options added to the view of the MVC framework are Html Helpers. These are optional code extensions that provide a short-hand to implementing form elements. Now an MVC purest may argue that no code, other than maybe data binding, should existing in the view. Fortunately, I have never been accused of being pure. Html Helpers provide an intuitive way to work with the strongly-type view data, and these helpers can make the view code more readable. There are plenty of resources on the web to show how to use Html Helpers here and here, and there are plenty of sites discussing how to create your own Html Helper extensions like Stephen Walther and Try-Catch-FAIL. This discussion is focused on a subclass of Helpers, block helpers, that have a variable amount of view code within them.
Block Helpers render Html code with separate open and close elements. One of the more common block helpers delivered with MVC is the Form helper. The Form Html Helper looks like:
<% using (Html.BeginForm(ActionName, ControllerName, data values, FormMethod, Html Attributes)) { %>
add some useful code or html elements here….
<% { %>
This help will render the begin and end form tags around the code placed within the Form. This helper has several overloads to provide a proper balance of flexibility and simplicity. This Helper returns an MVCForm object, and the BeginForm helper can be used with a separate EndForm helper instead of the “using” statement. One of the more common user-defined Html Helper extensions is the ImageLink. This Helper will wrap a link tag (“<a>”) around an image (“<img>”) tag. However, the image link wraps a single element within the link tag, and most of the implementations of this common helper return a single string like other inline Html Helpers.
However, suppose you need to define a tag (e.g. <div>, <a>, or<tr>) with attributes such as width or style or ID were determined by the data being bound to that part of the view and with a variable amount of html/code within the open and close tags. Embedding dynamic data within a Html tag is ugly at best. One simple approach would be to create a simple inline helper to build the opening tag based selected inputs, and then an appropriate close tag (e.g. </div>) can be manually placed in the view. However, a <% Html….%> helper paired with a native html close tag is not intuitive, and not easy to read – by VisualStudio or other developers. A better solution is a block helper. tvanfosson has created an excellent generic class to solve this problem. tvanfosson’s solution is relatively clean, straightforward and extensible. I would not try to improve on his solution as a foundation to other block helpers. However, as a generic solution, it defines a generic helper with Html.BeginContainer() and Html.EndContainer(). I extended this generic solution to some specific implementations to improve code readability. This following Html.Div() implementation is directly built upon tvanfosson’s solution, but it provides slightly more readable code in the view. Some one not familiar with HtmlHelpers or even the BeginContainer solution can deduce the meaning of the Html.Div helper.
public static class BoxerHTMLHelper
{
public static HelperContainer Div(this HtmlHelper helper, string id, string className, object htmlAttributes)
{
//Create Builder
var builder = new TagBuilder("div");
//set id and class
builder.GenerateId(id);
builder.AddCssClass(className);
//merger attributes
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
helper.ViewContext.HttpContext.Response.Write(builder.ToString(TagRenderMode.StartTag));
return new HelperContainer(helper.ViewContext.HttpContext.Response, "div");
}
}
public class HelperContainer : IDisposable
{
protected bool Disposed { get; set; }
protected HttpResponseBase HttpResponse { get; set;}
protected string Tag { get; set;}
// When the object is create, write "begin" function
public HelperContainer(HttpResponseBase httpResponse, string tag)
{
if (httpResponse == null)
{
throw new ArgumentNullException("httpResponse");
}
if (string.IsNullOrEmpty(tag))
{
throw new ArgumentNullException("tag");
}
this.HttpResponse = httpResponse;
this.Tag = tag;
}
// When the object is disposed (end of using block), write "end" function
public virtual void EndContainer()
{
this.Dispose(true);
}
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.Disposed)
{
this.Disposed = true;
this.HttpResponse.Write(string.Format("</{0}>", this.Tag));
}
}
#endregion
}
The key is the HelperContainer class. This class retains the HttpResponse handle, the tag used to create the object and a Disposed status. When the block is ended either through an appropriate Html Helper for an end tag or coming to the end of a using block, the Dispose method writes an appropriate close tag.
On the view page, this Div helper is a straight forward implementation.
<% using (Html.Div("", "cssclassname-1", new { style = "width: "+Model.widthValue+"px;" })) {%>
Html and view script code goes here...
<% } %>
This implementation is easy to read, it provides a clean implementation of a dynamic DIV tag, and it does not leave an unmatched </div> close tag to confuse Visual Studio.
9ae8df31-26c1-4f2b-8b6c-ca7f69248f47|0|.0