SPS Home    >   Dgreath    >   MVC MODELS

MVC Models

MVC models can be decorated with a variety of annotations to facilitate interfacing with data sources, provide user friendly nomenclature, manage rendering of data markup, and to implement server and client side validation.

The design process begins by declaring a class within an appropriate namespace for the models. The class is populated with public properties with accessors (getters) and mutators (setters) declared on each property. In the event that the model class requires fields that don't align with the data repository, you may need to create one or more inherited subclasses to handle the extended property set and add a constructor(s) as necessary to map those subclasses back to the parent class to avoid conflicts with your object relation modeling (ORM) implementation. An example of this would be where the model needs foreign key joins to other tables--these additional fields would be placed in the extended model and stripped out with the associated constructor. You may need to handle non-generic extension methods to translate the model into other formats.

Depending on the type of ORM implementation to be used, you may need to decorate the model and each of it's properties with appropriate vanity annotations. These typically relate the model property name to the actual column name in the database. Consult the documentation for the ORM implementation for the details on these as they are unique to each.

Next, apply the appropriate rendering annotations for DisplayName on the model, and Display on each property where needed. The various Html Helpers will always use those first when rendering with fallback to the actual property name, so the rendering annotation is only needed where the actual property name isn't suitable.

If the design calls for using the templated scaffolding system, you'll need to decorate each property with a suitable template annotations corresponding to the property's type. For properties where no suitable standard type is provided, the UIHint mechanism can be used for unique cases by creating partial views in both Shared/DisplayTemplates for the read only implementation and Shared/EditorTemplates for the read/write implementation.

Finally, if either client side or server side validation is contemplated via the model binding process, each property to be validated needs to be decorated with standard and possibly custom validation markup.

Note that data annotations are not all in one namespace. Check the referenced citation.


ORM Annotations

Each respective ORM implementation will have it's own annotations. Typical examples include:

Column

[Column("ColumnName")]

Can be applied to any property in the model to provide column name hint to the ORM.

Reference: System.ComponentModel.DataAnnotations.Schema.ColumnAttribute.cs

ForeignKey

[ForeignKey("ForeignTableName.ForeignColumnName")]

Can be applied to any foreign key property in the model to provide a join hint to the ORM.

Reference: System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute.cs

Key

[Key]

Can be applied to the primary key property of the model.

Reference: System.ComponentModel.DataAnnotations.KeyAttribute.cs

Table

[Table("TableName")]

Can be applied to the model class to provide table name hint to the ORM.

Reference: System.ComponentModel.DataAnnotations.Schema.TableAttribute.cs

Vanity

[Vanity("TABLE_NAME_ID")]

This is an example of a vanity annotation that could be applied to any property of the model to specify the exact name of the database field.


Rendering Annotations

The following annotations are used by all standard MVC Html helpers and assist in rendering properties in the view. These override the default property name:

Display

[Display(Name = "Name")]

Can be applied to any model property (either nontyped or strongly typed) to provide a user friendly name when rendered.

Reference: System.ComponentModel.DataAnnotations.DisplayAttribute.cs

DisplayName

[DisplayName("Name")]

Can be applied to the model class to provide a user friendly name when rendered. This is necessary for any of the "ForModel" helpers.

Reference: System.ComponentModel.DisplayNameAttribute.cs

DisplayFormat

[DisplayFormat(NullDisplayText = "")]
[DisplayFormat(ConvertEmptyStringToNull = true)]
[DisplayFormat(ApplyFormatInEditMode = true)]
[DisplayFormat(HtmlEncode = false)]
[DisplayFormat(NullDisplayText = "")]

Can be applied to any model property to handle null states of the property. NullDisplayText is used by read only displays. ConvertEmptyStringToNull is used by read/write editors—because this annotation executes before server side validation, it  may interfere with "required" validation.

Reference: System.ComponentModel.DataAnnotations.DisplayFormatAttribute.cs

Editable

[Editable]
[Editable(AllowEdit = true)]
[Editable(AllowInitialValue = true)]

Sets whether the property is read or read/write and whether an initial value is allowed.

Reference: System.ComponentModel.DataAnnotations.EditableAttribute.cs

ScaffoldColumn

[ScaffoldColumn(false)]

Can be applied to any model property to suppress automatic scaffolding when false.

Reference: System.ComponentModel.DataAnnotations.ScaffoldAttribute.cs

ScaffoldTable

[ScaffoldTable(false)]

Can be applied to any model class to suppress automatic scaffolding when false.

Reference: System.ComponentModel.DataAnnotations.ScaffoldAttribute.cs


MVC Models

Validation Annotations

The following annotations are used by MVC Html Validations Helpers during the server and optional client side validation process. These fields determine validation critera and error messages and will satisfy most validation needs. Custom validators can also be implemented:

Allow HTML

[AllowHtml]

Permits HTML characters to be entered into the field.

Reference: System.Web.Mvc.AllowHtmlAttribute.cs

Compare

[Compare("FieldToCompare")]
[Compare("FieldToCompare", ErrorMessage = "Custom error message."]

Performs a validation check to determine that the value of the current field matches the value of the specified field and renders either a default or custom error message.

Default Error Message:  ____ and _____ do not match.

Reference: System.ComponentModel.DataAnnotations.CompareAttribute.cs Note: in earlier versions (pre ) this was System.Web.Mvc.CompareAttribute.cs

CreditCard

[CreditCard]
[CreditCard(ErrorMessage = "Custom error message")]

For display, renders the plain text value. For editing, renders as a single line text box (<input type="text" />) with either a default or custom error message based on a Luhn algorithm. See [DataType(DataType.PhoneNumber] for rendering details.

Default Error Message:  The ____ field is not a valid credit card number.

Reference: System.ComponentModel.DataAnnotation.CreditCardAttribute.cs

Custom

[Custom]
[Custom(ErrorMessage = "Defined error message")]

For display, should render the plain text value. For editing, renders as a single line text box (<input type="text" />) with a defined error message based on a custom built validation process which could be a Regular Expression or the result of some computation.

In practice, the phrase "Custom" used here would be replaced by the actual name of the custom validator.

Reference: System.ComponentModel.DataAnnotation.CustomValidationAttribute.cs

EmailAddress

[EmailAddress]
[EmailAddress(ErrorMessage = "Custom error message")]

For display, renders the property as a clickable SMTP email link (href="mailto:). For editing, accepts input as a single line text box (<input type="text" />) with either a default or custom error message based on an internal Regular Expression. See [DataType(DataType.EmailAddress] for rendering details.

Default Error Message:  The ____ field is not a valid e-mail address.

Reference: System.ComponentModel.DataAnnotations.EmailAddressAttribute.cs

MaxLength

[MaxLength(20)]
[MaxLength(20, ErrorMessage = "Custom error message")]

Performs a length check and renders either a default or custom error message if the string or array length is greater than the specified maximum integer value.

Default Error Messages:  The field ____ must be a string or array type with a maximum length of ___ .

Reference: System.ComponentModel.DataAnnotations.MaxLengthAttribute.cs

MinLength

[MinLength(20)]
[MinLength(20, ErrorMessage = "Custom error message")]

Performs a length check and renders either a default or custom error message if the string or array length is less than the specified minimum integer value.

Default Error Messages:  The field ____ must be a string or array type with a minimum length of ___ .

Reference: System.ComponentModel.DataAnnotations.MinLengthAttribute.cs

Phone

[Phone]
[Phone(ErrorMessage = "Custom error message")]

For display renders the plain text value, For editing, renders as a single line text box (<input type="tel" />) with either a default or custom error message based on an internal Regular Expression evaluation. See [DataType(DataType.PhoneNumber)] for rendering details.

Default Error Message:  The ____ field is not a valid phone number.

Reference: System.ComponentModel.DataAnnotations.PhoneAttribute.cs

Required

[Required]
[Required(ErrorMessage = "Custom error message"]
[Required(AllowEmptyStrings = false)]

Performs a validation check to determine the field has some value and renders either a default or custom error message. AllowEmptyStrings needs to coordinate with DisplayFormat settings.

Default Error Message:  The ____ field is required.

Reference: System.ComponentModel.DataAnnotations.RequiredAttribute.cs

StringLength

[StringLength(20)]
[StringLength(20, MinimumLength = 10)] [StringLength(20, ErrorMessage = "Custom Error Message")]

Performs a string length check and renders either a default or custom error message if the string outside the specified minimum and/or maximum integer value(s).

Default Error Messages:  The field ____ must be a string with a minimum length of ___ and maximum length of ___ . —or—The field ____ must be string with a maximum length of ___.

Reference: System.ComponentModel.DataAnnotations.StringLengthAttribute.cs

Range

[Range(10,20]
[Range(10,20, ErrorMessage = "Custom Error Message."]

Checks the current value is greater than the specified minimum value and less than the specified maximum value and returns either the default or custom error message.

(short) Int16 maximum value: 32,767 Number(5)

(int) Int32 maximum value: 2,147,483,647 Number(10)

(long) Int64 maximum value: 9,223,372,036,854,775,807 Number(19)

Default Error Message:  The field ____ must be between ___ and _____.

Reference: System.ComponentModel.DataAnnotations.RangeAttribute.cs

RegularExpression

[RegularExpression("regEx")]
[RegularExpression("regEx", ErrorMessage = "Custom Error Message."]

Checks that the property entered is acceptable to the regular expression pattern. Either a default or custom error message is returned. In most cases, you'll want to use a custom error message here.

Default Error Message:  The field ____ must match the regular expression _____.

Reference: System.ComponentModel.DataAnnotations.RegularExpressionAttribute.cs

URL

[Url]
[Url(ErrorMessage = "Custom error message.")]

For display, renders the property as a clickable hyperlink (<a href="value"">value</a>). For editing, renders a single line text box <input text="url" />accepts input with either a default or custom error message based on an internal Regular Expression.

Default Error Message:  The ____ field is not a valid fully qualified http, https, or ftp URL.

Reference: System.ComponentModel.DataAnnotations.UrlAttribute.cs


Datatype Annotations

The following data annotations are used to determine the rendering for various common types of data field when used by the Display, Editor, and Label templated helpers. Additionally, certain annotations provide the validation described validation when called as noted. These annotations handle virtally all common primative types and several common complex types. For more complex situations,  UIHint is available to implement partial views. Additionally, custom implementations of any DataAnnotation can be derived from provided classes.

References:
System.Web.Mvc.Html.DisplayExtensions.cs
System.Web.Mvc.Html.DefaultDisplayTemplatess.cs
System.Web.Mvc.Html.EditorExtensions.cs
System.Web.Mvc.Html.DefaultEditorTemplates.cs
System.Web.Mvc.Html.TemplateHelpers.cs
System.ComponentModel.DataAnnotations.DataTypeAttribute.cs
System.ComponentModel.DataAnnotations.DataType.cs

Boolean Default

Unless otherwise specifically annotated, Boolean values will render as follows:

Display Templates: renders as a checkbox (<input type="checkbox" />)

Editing Templates: renders as a checkbox (<input type="checkbox" />)

Reference: System.ComponentModel.DataAnnotations

CreditCard

[DataType(DataType.CreditCard)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which will accept any string input. If validation is desired used [CreditCard]

Reference: System.ComponentModel.DataAnnotations

Currency

[DataType(DataType.Currency)]

Display Templates: renders as plain text value with the data format string set to {0:C} (i.e. $1.00).

Editing Templates: renders as a single line text box control <input type="number" />. (Number picker spin box) which only accepts numeric input.

Reference: System.ComponentModel.DataAnnotations.DataTypeAttribute.cs

Custom

[DataType(DataType.Custom)]

Display Templates: should render as plain text value.

Editing Templates: should render as a single line text box control <input type="text" />.

This will not work until implemented in code! As a practical matter, you would use UIHint, infra, to point to a partial view holding the custom implementation instead.

Reference: System.Web.DynamicData.FieldTemplateControl.cs

Date

[DataType(DataType.Date)]

Display Templates: renders as a plain text value with the data format string to {0:d}, the short date specifier (i.e. 6/16/2016).

Editing Templates: Renders as a single line text box control <input type="date" />. (Date picker spin box) which only accepts valid date input.

Reference: System.ComponentModel.DataAnnotations.DataTypeAttribute.cs

DateTime

[DataType(DataType.DateTime)] [DataType(DataType.DateTime, ErrorMessage = "Custom error message.")]

Display Templates: renders as plain text value.

Editing Templates: renders as a single line text box control <input type="datetime />.which only accepts datetime input. However, if the date and time typed in won't resolve to a valid datetime, it will throw either the default or custom error message based on an internal Regular Expression. In most cases, the Date or Time datatypes will provide a nicer user experience, however, in cases where both date and time must be entered, you have this control. Validation only checks that the format of the entered value is correct.

Default Error Message:  The ____ field must be a date.

Reference: System.ComponentModel.DataAnnotations

Decimal Default

Unless otherwise specifically annotated decimal values will render as follows:

Display Templates: renders the plain text value with format string set to {0:d} (i.e. 1.00).

Editing Templates: renders as a single line textbox (<input type="text" />) which allows decimal points, commas, and plus/minus signs to be entered.

Reference: System.ComponentModel.DataAnnotations

Duration

[DataType(DataType.Duration)]

Display Templates: renders as plain text value.

Editing Templates: renders as a single line text box control <input type="number" />. (Number picker spin box) which only accepts numeric input.

Reference: System.ComponentModel.DataAnnotations

EmailAddress

[DataType(DataType.EmailAddress)]

Display Template: renders the property as a clickable hyperlink (<a href="mailto: value"">value</a>).

Editing Template: Renders as a single line text box control <input type="email" /> which will accept any string input.  If validation is desired use [EmailAddress] instead.

Reference: System.ComponentModel.DataAnnotations

HiddenInput

[HiddenInput]

Display Templates: renders as plain text value.

Editing Templates:renders as a single line textbox (<input type="hidden" />) which will accept any string input.

Reference: System.ComponentModel.DataAnnotations

Html

[DataType(DataType.Html)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which will accept any string input.

Reference: System.ComponentModel.DataAnnotations

ImageUrl

[DataType(DataType.ImageUrl)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which will accept any string input.

Reference: System.ComponentModel.DataAnnotations

MultiLineText

[DataType(DataType.MultiLineText]

Display Templates: renders the plain text value.

Editing Templates: renders as a multiline TextArea control which will accept any string input.

Reference: System.ComponentModel.DataAnnotations

Numeric Default

Unless otherwise specifically annotated byte, sbyte, int, uint,long, and ulong values will render as follows:

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="number" />)

Reference: System.ComponentModel.DataAnnotations

Password

[DataType(DataType.Password)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line password textbox (<input type="password" />) which will accept any string input but will obfuscate the input to the viewer so it cannot be viewed while being input.

Reference: System.ComponentModel.DataAnnotations.PasswordAttribute.cs

PhoneNumber

[DataType(DataType.PhoneNumber)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="tel" />) which will accept any unvalidated string input. If validation is desired, use [Phone] instead.

Reference: System.ComponentModel.DataAnnotations

PostalCode

[DataType(DataType.PostalCode)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which will accept any string input. If validation is needed, either implement a RegEx validator or write a custom validator.

Reference: System.ComponentModel.DataAnnotations

String Default

Unless otherwise specifically annotated, string values will render as follows:

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which allows any text to be entered.

Reference: System.ComponentModel.DataAnnotations

Text

[DataType(DataType.Text)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which will accept any string input.

Reference: System.ComponentModel.DataAnnotations

Time

[DataType(DataType.Time)]

Display Templates: renders as plain text value with the data format string set to {0:t}, the short time specifier (i.e. 1:45 PM).

Editor Templates: renders as a single line text box <input type="time" /> (Time picker spin box) which only accepts valid time input.

Reference: System.ComponentModel.DataAnnotations.DataTypeAttribute.cs

Upload

[DataType(DataType.Upload)]

Display Templates: renders the plain text value.

Editing Templates: renders as a single line textbox (<input type="text" />) which will accept any string input. Consider writing a custom HtmlHelper to handle file uploading.

Reference: System.ComponentModel.DataAnnotations

URL

[DataType(DataType.Url)]

Display Template: renders the property as a clickable hyperlink (<a href="value"">value</a>).

Editing Template: Renders as a single line text box control <input type="url" /> which will accept any string input.  If validation is desired use [Url] instead.

Reference: System.ComponentModel.DataAnnotations

UIHint

[UIHint("partialview")]

Can be applied to any model property to point to custom partial views when no standard template applies. You need two: the read only implementation placed in the "Views/Shared/DisplayTemplates" folder and the read/write implementation placed in the "Views/Shared/EditorTemplates" folder.

Reference: System.ComponentModel.DataAnnotations.UIHintAttribute.cs