Series Index
- Part 1: Introduction
- Part 2: ModelMetadata
- Part 3: Default Templates
- Part 4: Custom Object Templates
- Part 5: Master Page Templates
Understanding Your Model
One of the classes we introduced with ASP.NET MVC 2 is ModelMetadata. This class is designed to tell you interesting things about the objects you want to display or edit. While we commonly use them when writing templates, this metadata is actually always available, even when you’re not in a template.
What is a Model?
When it comes to ModelMetadata, the definition of “model” is probably a bit blurrier than you’re used to.
Let’s say for instance that you have the model from part 1 of this blog series:
public class Contact {
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
You created a strongly-typed view for this model, and if inside the view you access ViewData.ModelMetadata, then the model at this point is the Contact object.
However, through this metadata object, you can also get metadata about all of its properties. This returns a collection of ModelMetadata objects, one for each of the properties. If we were to do this with our Contact object, we’d end up with 3 new metadata objects, one each for FirstName, LastName, and Age. When you’re looking at the model metadata for FirstName, the model type is String (and the container type is Contact). In this way, you can even recursively dive through several layers of complex objects via properties.
How Do I Get One?
Use the one for the current model.
The most common way to get one is to access the ModelMetadata property on ViewData as shown above. This metadata object describes the ViewData’s Model. When you’re rendering a template for an object, this is the most common way to get metadata.
Get one for properties on metadata you already have.
If you have a metadata object in hand, you can call the Properties property, which returns a list of ModelMetadata objects for each of the properties of that model.
Get one from an expression.
The ModelMetadata class has two static methods on it: FromStringExpression and FromLambdaExpression. These are the methods that are used when you want to turn a string expression (like “PropertyName”) or a code-based expression (like “m => m.PropertyName”) into the appropriate ModelMetadata. Most of the existing HTML helpers have been re-written in terms of these two methods, so that they exhibit consistent parsing of expressions (and can use the ModelMetadata to make better decisions about how to display objects).
What’s Inside Of One?
Before we talk about how ModelMetadata is populated, let’s quickly review what kind of information is available inside of a ModelMetadata object.
Properties about the model and its container
- Model and ModelType
Retrieves the value and type of the model itself. Although the model value itself may be null, we may still know the type of the model (for example, we can derive that information from the lambda expression). - ContainerType and PropertyName
Retrieves the type of the container object and the name of the property that this value came from. Not all models come from properties, so these may be null. - Properties
Retrieves a collection of ModelMetadata objects which describe the properties of the existing model.
Metadata about the model
- ConvertEmptyStringToNull
A flag which indicates whether empty strings that are posted back in forms should be converted into NULLs. Default: true - DataTypeName
A string which can used to give meta information about the data type (for example, to let you know that this string is actually an e-mail address). Some well-known data type names include “EmailAddress”, “Html”, “Password”, and “Url”. Default: null - Description
A long-form textual description of this model. Default: null - DisplayFormatString
A format string that will be used when displaying this model value in a template. Default: null - DisplayName
The display name of this model value. Used in templates and Html.Label/LabelFor to generate the label text. Default: null - EditFormatString
A format string that will be used when editing this model value in a template. Default: null - HideSurroundingHtml
A flag which indicates that this field should not have any of its surrounding HTML (for example, a label). Often used when a template will be generating a hidden input. Default: null - IsComplexType
A flag which indicates whether the system considers this to be a complex type (and therefore will default to the complex object template rather than the string template). Not user-settable - IsNullableValueType
A flag which indicates whether the model is a nullable value type (namely, Nullable<T>). Not user-settable - IsReadOnly
A flag which indicates if this value is read-only (for example, because the property does not have a setter). Default: false - IsRequired
A flag which indicates if this value is required. Default: true for non-nullable value types; false for all others. - NullDisplayText
The text which should be used when attempting to display a null model. Default: null - ShortDisplayName
The short display name of this mode value. Intended to be used in the title of tabular list views. If this field is null, then DisplayName should be used. Default: null - ShowForDisplay
A flag which indicates if this model should be shown in display mode. Default: true - ShowForEdit
A flag which indicates if this model should be shown in edit mode. Default: true - SimpleDisplayText
Text which should be shown for this model when summarizing what would otherwise be a complex object display. Default: see below - TemplateHint
A string which indicates a hint as to what template should be used for this model. Default: null - Watermark
Text that might be displayed as a watermark when editing this model in a text box. Default: null
Helper methods
- GetDisplayName()
This method can be used to get a display name for the model. If DisplayName is not null, it returns that; then it checks if PropertyName is not null, and if so it returns that; failing all those, it returns ModelType.Name. - GetValidators()
This method can be used to retrieve the validators that are applicable for this model. These can be used to either run server-side validation on this model, or to generate the client-side validation rules.
The default value for SimpleDisplayText follows these rules:
- If the Model is null, return NullDisplayText
- If the type has overridden the value of Model.ToString(), then return that
- If the model has no properties, return String.Empty
- If the model’s first property is null, then return that property’s NullDisplayText value
- Otherwise, return the model’s first property’s ToString() value
Where Does ModelMetadata Come From?
We’ve added a pluggable metadata provider system in ASP.NET MVC 2. By default, the ModelMetadata objects are constructed with data taken from attributes, primarily from the System.ComponentModel and System.ComponentModel.DataAnnotations namespaces.
When using the default DataAnnotations model metadata provider, the following attributes will influence model metadata:
- [HiddenInput] (from System.Web.Mvc)
Applying this attribute will generate a hidden input when editing this model. By default, it will also hide all the surrounding HTML, unless you set the DisplayValue flag to be true; in this case, it will generate both a displayed value (with its surrounding HTML) and the hidden input. In addition to setting HideSurroundHtml, it also sets a TemplateHint of “HiddenInput” (which can be overridden with [UIHint]) - [UIHint] (from System.ComponentModel.DataAnnotations)
This will set the TemplateHint property with the name of the UI hint. We first look for a PresentationLayer type of “MVC”, and if there isn’t one, look for an empty or null PresentationLayer. - [DataType] (from System.ComponentModel.DataAnnotations)
This will set the DataTypeName property. - [ReadOnly] (from System.ComponentModel)
This will set the IsReadOnly property. Note that because we use Type descriptors, any property without a public setter will have the [ReadOnly] attribute automatically. - [DisplayFormat] (from System.ComponentModel.DataAnnotations)
Setting NullDisplayText on this attribute sets NullDisplayText on model metadata. Setting DataFormatString will set DisplayFormatString on model metadata; if ApplyFormatInEditMode is set to true, then it will also set the EditFormatString on model metadata. Setting ConvertEmptyStringToNull on the attribute will set ConvertEmptyStringToNull on model metadata. - [ScaffoldColumn] (from System.ComponentModel.DataAnnotations)
This will set both the ShowForDisplay and ShowForEdit properties. - [DisplayName] (from System.ComponentModel)
This will set the DisplayName property.
Wrapping Up
Now we know a little bit more about the metadata that’s available about your models when writing templates. In the next blog post, we’ll talk about the default templates that are built into ASP.NET MVC 2, and show what they would look like if you wrote them as .ascx files.