Creating reusable UI components for ASP.Net MVC

If you have not seen my MVC Themed Web App Visual Studio Project template yet, go check it out.

I was toying with an idea when I started the VS template but never got around to it…How do I create reusable UI components for a ASP.Net MVC website? What I mean is most websites consists of numerous elements, for example the sidebar widgets on this blog:

image.png

If you look closely the Recent Posts and Tag Cloud widget uses the exact same Html mark-up, only their contents differ. Wouldn’t it be great if I could write a simple ASP.Net MVC extension that would create the basic mark-up for the widget and then I only need to add the content?

The good news is, I’ve done it for the MVC Themed Web App Visual Studio Project template sidebar components. As you can see in the following screenshot, the standard sidebar consists of 3 UI elements, a Simple Block, Notice and a Sidebar Inner Block:

image.png

The html for these 3 components looks like:

After doing some digging in the ASP.Net source code, I’ve based my extension on the @Html.BeginForm helper. This means that the mark-up above can be replaced by the following:

<div id="sidebar">
    <div class="block">
        <h3>
            Simple Block
        </h3>
        <div class="content">
            <p>
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
                incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
                 exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
             </p>
         </div>
     </div>
     <div class="block notice">
         <h4>
             Notice Title
         </h4>
         <p>
             Morbi posuere urna vitae nunc. Curabitur ultrices, lorem ac aliquam blandit, lectus
             eros hendrerit eros, at eleifend libero ipsum hendrerit urna. Suspendisse viverra.
             Morbi ut magna. Praesent id ipsum. Sed feugiat ipsum ut felis. Fusce vitae nibh
             sed risus commodo pulvinar. Duis ut dolor. Cras ac erat pulvinar tortor porta sodales.
             Aenean tempor venenatis dolor.
         </p>
     </div>
     <div class="block">
         <div class="sidebar-block">
             <h4>
                 Sidebar Inner block Title
             </h4>
             <p>
                 Morbi posuere urna vitae nunc. Curabitur ultrices, lorem ac <a href="#">aliquam blandit</a>
                 , lectus eros hendrerit eros, at eleifend libero ipsum hendrerit urna. Suspendisse
                 viverra. Morbi ut magna. Praesent id ipsum. Sed feugiat ipsum ut felis. Fusce vitae
                 nibh sed risus commodo pulvinar. Duis ut dolor. Cras ac erat pulvinar tortor porta
                 sodales. Aenean tempor venenatis dolor.
             </p>
         </div>
     </div>
 </div>

You’ll notice that I’ve created three helpers, one for each different style of sidebar widget. I then only need to specify the widgets’ Title as a parameter and add the widget content as standard html.

To use this in your own ASP.Net MVC project based on my Themed App project template, simply create a new folder called Infrastructure and add a HtmlHelper.cs class to it:

using System;
using System.Web.Mvc;

namespace MVCThemedApp1.Infrastructure
{
    public static class HtmlHelper
    {
        public static ThemedBox NoticeBlock(this System.Web.Mvc.HtmlHelper html, 

         string title)
        {
            TagBuilder divBuilder = new TagBuilder("div");
            divBuilder.AddCssClass("block notice");
            html.ViewContext.Writer.Write(String.Format("{0}<h4>{1}</h4>", 

            divBuilder.ToString(TagRenderMode.StartTag), title));

            ThemedBox theBox = new ThemedBox(html.ViewContext);
            return theBox;
        }

        public static ThemedBox InnerBlock(this System.Web.Mvc.HtmlHelper html, 

          string title)
        {
            TagBuilder blockDiv = new TagBuilder("div");
            blockDiv.AddCssClass("block");
            html.ViewContext.Writer.Write(blockDiv.ToString(TagRenderMode.StartTag));

            TagBuilder divBuilder = new TagBuilder("div");
            divBuilder.AddCssClass("sidebar-block");
            html.ViewContext.Writer.Write(String.Format("{0}<h4>{1}</h4>", 

            divBuilder.ToString(TagRenderMode.SelfClosing), title));

            ThemedBox theBox = new ThemedBox(html.ViewContext,2);
            return theBox;
        }

        public static ThemedBox SimpleBlock(this System.Web.Mvc.HtmlHelper html, string title)
        {
            TagBuilder blockDiv = new TagBuilder("div");
            blockDiv.AddCssClass("block");
            html.ViewContext.Writer.Write(String.Format("{0}<h3>{1}</h3>", blockDiv.ToString(TagRenderMode.StartTag), title));

            TagBuilder contentDiv = new TagBuilder("div");
            contentDiv.AddCssClass("content");            
            html.ViewContext.Writer.Write(contentDiv.ToString(TagRenderMode.SelfClosing));

            ThemedBox theBox = new ThemedBox(html.ViewContext,2);
            return theBox;
        }
    }
}

Next, you also need to add a new class called ThemedBox.cs to the Infrastructure folder:

using System;
using System.Web;
using System.Web.Mvc;
using System.IO;

namespace MVCThemedApp1.Infrastructure
{
    public class ThemedBox : IDisposable
    {
        private bool _disposed;
        private readonly ViewContext _viewContext;
        private readonly TextWriter _writer;
        private int NumberOfClosingDivs = 1;

        public ThemedBox(HttpResponseBase httpResponse)
        {
            if (httpResponse == null)
            {
                throw new ArgumentNullException("httpResponse");
            }

            _writer = httpResponse.Output;
        }

        public ThemedBox(ViewContext viewContext, int numberOfClosingDivs=1)
        {
            if (viewContext == null)
            {
                throw new ArgumentNullException("viewContext");
            }
            NumberOfClosingDivs = numberOfClosingDivs;
            _viewContext = viewContext;
            _writer = viewContext.Writer;
        }

        public void Dispose()
        {
            Dispose(true /* disposing */);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                _disposed = true;

                for (int i = 1; i <= NumberOfClosingDivs; i++)
                {
                    _writer.Write("</div>");
                }                

                if (_viewContext != null)
                {
                    _viewContext.OutputClientValidation();
                }
            }
        }
    }
}

You would need to compile your solution first in order for the Html helper to become available and as easy as that you have an easy reusable UI component.

The other good news is that if you created your project based on the MVC Themed App project template, the widgets will also be automatically themed

If you have any comments or questions, please feel free to ask leave a comment or drop me a line on Twitter.