One of the things we got a peek at with MVC Futures when Asp.net mvc 2 was the use of syntax like this in markup (it’s en Expression<Func<TModel,Tvalue>> where TModel is the objecttype to get the value from and TValue is the expected type):

Which means that instead of those Harry Potter strings. You use an Expression for determining the name and value. But like when I eat spicy food it comes with a price. And for this approach it comes with a significant performance penalty http://blog.whiletrue.com/2009/04/aspnet-mvc-performance/ (especially slide nr 25).
I guess that it was one of the main reasons it was in the futures and not in the released version. But they are included in RC and I have been looking through the source code for mvc 2 rc and it seems that the development teem have put some effort into making it more perform better.
What happens is the following (this example is based on the LabelFor but it seems to be the same “general” approach for other extension methods like TextBoxFor, TextAreaFor etc.
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression) {
return LabelHelper(html,
ModelMetadata.FromLambdaExpression(expression, html.ViewData),
ExpressionHelper.GetExpressionText(expression));
}
Two method are called for the last to parameters for the LabelHelper.
1 ModelMetaData.FromLamdaExpression
The Expression and the viewdata is passed in as parameters to the static method FromLamdaExpression which returns a ModelMetadata object. As the name implies it stores a wide array of metadata related to a model.
The method performs some null checks, redirects to a different method if you reference the same object (model => model). And throws and exception if it’s not a MemberAccess expression (lookup of a value).
Then this happens:
TParameter container = viewData.Model;
Func<object> modelAccessor = () =>
{
try {
return CachedExpressionCompiler.Process(expression)(container);
}
catch (NullReferenceException) {
return null;
}
};
Now the real compilation begins. And this is at least one of the points where performance is taken into consideration. The Process method of the CachedExpressionCompiler goes through three steps to assign the compiled Func to the modelAccessor property as fast as possible. On success it returns the compiled function. Basically this is what happens:
- GetFuncFastTrack. It catches simple expression like model => model, model => 42(constant value), model => StaticClass.Member and model => model.Property. It’s uses a large degree of caches to perform the lookup.
- GetFuncFingerprinted. The uses a mechanism where it gets a fingerprint (an id used to identify the signature of an expression) are created and matched against a cache.
- GetFuncSlow. (Or the good old fashion Compile call)
The end of the FromLamdaExpression looks like this
MemberExpression memberExpression = (MemberExpression)expression.Body;
string propertyName=memberExpression.Member is PropertyInfo ? memberExpression.Member.Name:null;
Type containerType = memberExpression.Member.DeclaringType;
return GetMetadataFromProvider(modelAccessor, typeof(TValue), propertyName, containerType);
The short story. modelAccesor, resultype, propertyname and containerType of the property is passed into GetMetadataFromProvider method. Besides the inputted parameter values it further enrich the ModelMetadata object. But that seems be material for completely different blog post.
2 ExpressionHelper.GetExpressionText
The second method is the one that generates the Name to be entered
public static string GetExpressionText(LambdaExpression expression) {
// Crack the expression string for property/field accessors to create its name
Stack<string> nameParts = new Stack<string>();
Expression part = expression.Body;
while (part != null) {
if (part.NodeType == System.Linq.Expressions.ExpressionType.MemberAccess) {
MemberExpression memberExpressionPart = (MemberExpression)part;
nameParts.Push(memberExpressionPart.Member.Name);
part = memberExpressionPart.Expression;
}
else {
break;
}
}
// If it starts with "model", then strip that away
if (nameParts.Count > 0 && String.Equals(nameParts.Peek(), "model",
StringComparison.OrdinalIgnoreCase)) {
nameParts.Pop();
}
if (nameParts.Count > 0) {
return nameParts.Aggregate((left, right) => left + "." + right);
}
return String.Empty;
}
It does the following. It creates a stack of string. And as long as the current part isn’t null it' pushes the name of the member to the stack. Lets take this expression. model => model.First.Second.Third. The first one it will hit is Third. So the stack will look like this at the end:
First
Second
Third.
It then aggregates (join) these together to the composite string.
If the first and only name is model. It’s removed. I haven’t quite figured that one out yet. It seems be a reserved keyword that you don’t want to use as name in the markup D’oh! It’s the name of the container of ViewData.Model
LabelHelper
The result it that the ModelMetadata and the generated namestring is passed in to the LabelHelper. Which generates the label.
internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata,
string htmlFieldName) {
string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName
.Split('.').Last();
if (String.IsNullOrEmpty(labelText)) {
return MvcHtmlString.Empty;
}
TagBuilder tag = new TagBuilder("label");
tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo
.GetFullHtmlFieldId(htmlFieldName));
tag.SetInnerText(labelText);
return tag.ToMvcHtmlString(TagRenderMode.Normal);
}
See that if you have used the if DisplayName in the metadata is not null it sets this value to the label (You can set a DisplayName attribute on your objects properties). This method is internal but it uses a TagBuilder class which on the other hand is public.
public static string GetExpressionText(LambdaExpression expression) {
// Crack the expression string for property/field accessors to create its name
Stack<string> nameParts = new Stack<string>();
Expression part = expression.Body;
while (part != null) {
if (part.NodeType == System.Linq.Expressions.ExpressionType.MemberAccess) {
MemberExpression memberExpressionPart = (MemberExpression)part;
nameParts.Push(memberExpressionPart.Member.Name);
part = memberExpressionPart.Expression;
}
else {
break;
}
}
// If it starts with "model", then strip that away
if (nameParts.Count > 0 && String.Equals(nameParts.Peek(), "model",
StringComparison.OrdinalIgnoreCase)) {
nameParts.Pop();
}
if (nameParts.Count > 0) {
return nameParts.Aggregate((left, right) => left + "." + right);
}
return String.Empty;
}
The last thing to take notice of is the MvcHtmlString being returned by the LabelHelper. Here's the information copied directly from the comments, but basically you should use this if create any kind of helper or extensionmethod that can be used in the view:
// In ASP.NET 4, a new syntax <%: %> is being introduced in WebForms pages, where <%: expression %> is equivalent to
// <%= HttpUtility.HtmlEncodeexpression) %>. The intent of this is to reduce common causes of XSS vulnerabilities
// in WebForms pages (WebForms views in the case of MVC). This involves the addition of an interface
// System.Web.IHtmlString and a static method overload System.Web.HttpUtility::HtmlEncode(object). The interface
// definition is roughly:
// public interface IHtmlString {
// string ToHtmlString();
// }
// And the HtmlEncode(object) logic is roughly:
// - If the input argument is an IHtmlString, return argument.ToHtmlString(),
// - Otherwise, return HtmlEncode(Convert.ToString(argument)).
//
// Unfortunately this has the effect that calling <%: Html.SomeHelper() %> in an MVC application running on .NET 4
// will end up encoding output that is already HTML-safe. As a result, we're changing out HTML helpers to return
// MvcHtmlString where appropriate. <%= Html.SomeHelper() %> will continue to work in both .NET 3.5 and .NET 4, but
// changing the return types to MvcHtmlString has the added benefit that <%: Html.SomeHelper() %> will also work
// properly in .NET 4 rather than resulting in a double-encoded output. MVC developers in .NET 4 will then be able
// to use the <%: %> syntax almost everywhere instead of having to remember where to use <%= %> and where to use
// <%: %>. This should help developers craft more secure web applications by default.
// To create an MvcHtmlString, use the static Create() method instead of calling the protected constructor
That’s all for now. I wish you a merry christmas.
And as always remember to stay clear of the dark side of the force