Um wiederkehrende Aufgaben zu automatisieren, bieten sich benutzerdefinierte HTML-Helper für ASP.NET MVC an. Eine Möglichkeit, dies zu bewerkstelligen steht im Bereitstellen von Erweiterungsmethoden für die Klasse HtmlHelper<T>.
Möchte man im Zuge dessen auch einen Lambda-Ausdruck, der auf eine Eigenschaft im Model verweist, entgegennehmen, ist der Erweiterungsmethode ein Parameter vom Typ Expression<Func<Model, Property>> zu spendieren. Für diese Expression kann man sich über ModelMetadata.FromLambdaExpression(expr, html.ViewData) eine Instanz von ModelMetadata, welch die gewünschte Model-Eigenschaft repräsentiert, abrufen. Der erste Parameter (expr) ist hierbei die Expression. Bei der im Rahmen des zweiten Parameters verwendeten Variable html handelt es sich um den HtmlHelper. Über die Eigenschaft Model von ModelMetadata kann man anschließend den Wert der vom Aufrufer angegebenen Mode-Eigenschaft in Erfahrung bringen. Mit Model wird hierbei somit, wie so häufig, lediglich ein Teil des Models bezeichnet.
Ein Beispiel für solch eine Erweiterungsmethode findet sich im nachfolgenden Listing.
namespace System.Web.Mvc.Html
{
public static class ListHelper
{
public static IHtmlString UnorderedList<Model, Property>(this HtmlHelper<Model> html, Expression<Func<Model, Property>> expr)
{
var metadata = ModelMetadata.FromLambdaExpression(expr, html.ViewData);
if (metadata == null || metadata.Model == null) return new HtmlString("");
var entries = metadata.Model as IEnumerable<object>;
if (entries == null) return new HtmlString("");
var buffer = new StringBuilder();
buffer.Append("<ul>\n");
foreach (var obj in entries)
{
buffer.AppendFormat(" <li>{0}</li>\n", obj.ToString());
}
buffer.Append("</ul>\n");
return new HtmlString(buffer.ToString());
}
}
}
Damit die Erweiterungsmethode von der Razor-Engine gefunden wird, ist sie innerhalb eines Namespaces zu platzieren, der standardmäßig in Views eingebunden wird. Diese Namespaces sind in der Datei Views/Web.config registriert (siehe nächstes Listing) und es besteht die Möglichkeit, mit eigenen Add-Elementen weitere, benutzerdefinierte, hinzuzufügen. Im soeben betrachteten Listing wurde zur Vereinfachung der standardmäßig registrierte Namespace System.Web.Mvc.Html herangezogen.
<system.web.webPages.razor>
[…]
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization"/>
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
Anschließend kann die Erweiterungsmethode in Views verwendet werden:
@Html.UnorderedList(m => m.ProductNames)