Steve Andrews

passionate technologist · business applications · community guy

DevEvents: More .NET MVC HtmlHelpers

In my last post, I showed how I used an HtmlHelper to create an enumerable-based dropdown. In this post, I’ll share a few more HtmlHelpers I’ve created to make life easier, or the user experience better.

There are places in DevEvents, like the directory listings where it would not be optimal to display the whole text of a speaker or event description. In such cases, I use an HtmlHelper to truncate the text, and optionally append a ‘more info’ link. To make it even better, you might consider finding the next space (‘ ‘), and truncating there.

public static string TruncateText(this HtmlHelper helper, string text, int maxLength, string postFix)
{
if (text != null && text.Length > maxLength)
return text.Substring(0, maxLength) + postFix;

return text;
}

ResolveUrl is a very handy method, but it isn’t available everywhere I needed it to be, like inside other HtmlHelpers, so I created my own ResolveUrl HtmlHelper.

public static string ResolveUrl(this HtmlHelper helper, string url)
{
if (url.StartsWith("~/"))
{
string siteRoot = helper.ViewContext.HttpContext.Request.ApplicationPath;

if (siteRoot == string.Empty)
siteRoot =
"/";

return url.Replace("~/", siteRoot);
}
else
{
return url;
}
}

The HTML construct of ‘<label for’ is very helpful for individuals with accessibility issues and non-standard browsers. Instead of having to write out the whole HTML every time, I created an HtmlHelper:

public static string LabelFor(this HtmlHelper helper, string target, string text)
{
return String.Format("<label for='{0}'>{1}</label>", target, text);
}

One common website complaint is that text is not pluralized correctly. I created a very simple HtmlHelper to do just this:

public static string PluralizeText(this HtmlHelper helper, string singularText, string pluralText, int number)
{
if (number == 1)
return singularText;
else
return
pluralText;
}
You may wish to pass in HTML attributes to one or more of your HtmlHelpers, but how do you append them to the output? Here is a simple example showing how to append HTML attributes using a dictionary. Arguably this functionality could be an HtmlHelper itself. Notice it also utilizes the ResolveUrl HtmlHelper. (Updated: 1/14/2009: Removed some redundancy thank to Marc’s comments below
public static string Image(this HtmlHelper helper, string url, object htmlAttributes)
{
StringBuilder sb = new StringBuilder();
sb.Append(
"<img src=\"" + helper.ResolveUrl(url) + "\"");

IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);

if (attributes != null)
{
foreach (var item in attributes) { sb.Append(" " + item.Key + "=\"" + item.Value.ToString() + "\""); }
}

sb.Append(
" />");

return sb.ToString();
}

The introduction of anonymous types, generics, and other .NET 3.0 features also introduces some complexity when working with Nullable types. To facilitate these scenarios, I created the following HtmlHelper: (Updated 1/14/2009: Made it a generic method thanks to Liam’s comment below)

public static string FormatNullable<T>(this HtmlHelper helper, Nullable<T> nullable, string format, string emptyText) 
    where T : struct
{
    if (nullable.HasValue)
        return string.Format(format, nullable.Value);
    else
        return emptyText;
}

Hopefully you will find one or more of these HtmlHelpers helpful in your .NET MVC development. What custom HtmlHelpers do you use? Would you do any of these differently?

Comments (6) -

  • Marc Brooks

    9/2/2013 4:53:56 PM |

    That last method looks like a Reflector decompile... especially:


      string key = Convert.ToString((string)pair1.Key, CultureInfo.InvariantCulture);


    Clearly, that's just:


     string key = (string)pair1.Key;


    I would also worry that attribute values could sometimes be things that should be rendered in CurrentCulture.


  • PaulBlamire

    9/2/2013 4:53:56 PM |

    Nice artice,


    If you used System.Web.Mvc.TagBuilder too you could cut back on the code even more, for instance:


           public static string Image(this HtmlHelper helper, string url, object htmlAttributes)


           {


               StringBuilder sb = new StringBuilder();


               TagBuilder tag = new TagBuilder("img");


               tag.MergeAttribute("src", helper.ResolveUrl(url));


               IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);


               tag.MergeAttributes<string, object>(attributes);


               return tag.ToString(TagRenderMode.SelfClosing);


           }


  • Liam McLennan

    9/2/2013 4:53:56 PM |

    I think FormatNullable could use generics to reduce the need for overloads.


    public static string FormatNullable<T>(this HtmlHelper helper, Nullable<T> nullable, string format, string emptyText)


    {


       if (nullable.HasValue)


           return string.Format(format, nullable.Value);


       else


           return emptyText;


    }


  • stevanich

    9/2/2013 4:53:56 PM |

    @Elijah: I don't have an algorithm like that. In the case of 'one fish, two fish', I just wouldn't use the HtmlHelper. Great links too!


    @Marc: I removed the redundancy, thanks!


    @Paul: I was not aware of TagBuilder. It looks like it'll definitely help remove unnecessary code in places.


    @Liam: As listed, you will receive an error: "The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>". I appended "where T : struct", and it is working fine. Thanks!


Pingbacks and trackbacks (2)+

Comments are closed
Steve Andrews | Tips for Releasing Sample Code

Steve Andrews

passionate technologist · business applications · community guy

Tips for Releasing Sample Code

When I’m learning a new technology, I’ll frequently download code samples that help me better understand the concepts. Often though I find myself frustrated by having to deal with formatting and extraneous information before even looking at the code. To that end I have some rules for releasing sample code.

Format Every Document
The keyboard shortcut for this is Ctrl+K+D. Nothing is more frustrating than looking at unformatted code.

Code Order
Code should be ordered in the following structure from top to bottom:

  • events
  • fields and automatic properties
  • constructors
  • abstract methods
  • methods
  • abstract properties
  • properties
  • subclasses

Code Statements
Include a blank line before return statements and before and after decision blocks (including using, if, switch, while). In C#, opening and closing brackets should be on their own line.

Remove Excess Blank Lines
There should never be more than one consecutive blank line between any lines of code. With consecutive closing brackets as well as #endregion notations in C#, there should be no blank lines between them. There should also be no blank lines between fields or at the beginning or end of method or property bodies.

Separate Code
There should be one blank link between properties and methods to allow the user to see logical breaks in the code.

Code Files
There should only be one class, interface or enumeration per file.

XML Comments
Always remove unnecessary XML comments from your code files. For example, this XML comment should be removed:

/// <param name="param"></param>

Import Namespace Placement
Import (C#) or using (VB) directives should be placed above the namespace. Also use the Organize Usings > Remove and Sort refactoring built-in to Visual Studio 2008 and Visual Studio 2010 to remove any unnecessary directives. This also helps to make the directives more readable.

Wrapping Lines
Don’t manually wrap long lines of code. Visual Studio has a feature to allow a user to wrap long lines if they so choose.

Properties
Use automatic properties in .NET 3.0 code and above whenever possible.

These are a few of the rules. I’ll try to keep the list updated as I run across more frustrations.

Comments (2) -

  • Steve Evans

    9/2/2013 4:53:56 PM |

    My preference would be for projects to make use of style guidelines/tools that already exist.  So C# projects should be using StyleCop.  The key is to not change the default settings that are installed on the machine, but instead customize them per solution/project.


  • Anil

    9/2/2013 4:53:56 PM |

    Hi Steve,


    I see it's an old post but I just found it and I have a question.


    I really pay attention to the structure of code (some say too much) and I couldn't agree more about practicing Ctrl+K+D.


    I put extra effort in following MS guidance / conventions about code formating, naming, etc., but there is one thing I could not find (maybe I didn't search enough)  and it is the "Code Order" you mentioned in the post.


    I had my own convention and stuck with it in hope that I will find the official one someday.


    So, Is this order of code, proposed in the post, actually the official one or your own convention?


    Thanks!


    Anil


Pingbacks and trackbacks (3)+

Comments are closed