New features in ASP.NET MVC 2 Preview

New Features

This section describes features that have been introduced in the MVC 2 Preview 2 release.

ModelMetadata and ModelMetadataProvider Classes

The ModelMetadataProvider class provides an abstraction for obtaining metadata for the model within a view. MVC includes a default provider which surfaces the metadata that is exposed by the attributes in the System.ComponentModel.DataAnnotations namespace. It is possible to create metadata providers that provide metadata from other data stores, databases, XML files, and so on.

The ViewDataDictionary class exposes a ModelMetada object that contains the metadata that is extracted from the model by the ModelMetadataProvider class. This allows the templated helpers to consume this metadata and adjust their output accordingly.

For more information, see the documentation for ModelMetadata and ModelMetadataProvider.

Model Validator Providers

The model validation providers class provides an abstraction for obtaining validation logic for the model. ASP.NET MVC includes a default provider based on Data Annotations validation attributes that are included in the System.ComponentModel.DataAnnotations namespace. You can also create custom validation providers that define custom validation rules and custom mappings of validation rules to the model. For more information, see the documentation for ModelValidatorProvider.

Client-Side Validation

The model validator provider class exposes validation metadata to the browser in the form of JSON-serialized metadata that can be consumed by a client-side validation library. The provider class allows you to use other client validation frameworks by writing an adapter that processes the JSON metadata and calls into the alternate client validation library.

ASP.NET MVC Preview 2 includes the jQuery validation library and a client-side validation adapter for that library. The adapter supports the following DataAnnotations namespace validation attributes:

· StringLengthAttribute

· RequiredAttribute

· RegexAttribute

· RangeAttribute

For a walkthrough of how to use client-side validation with ASP.NET MVC, see Client Side Validation in ASP.NET MVC on the MSDN Web site.

New Code Snippets for Visual Studio 2010

A set of HTML code snippets for MVC 2 is installed with Visual Studio 2010 Beta 2. To view a list of these snippets, in the Tools menu, select Code Snippets Manager. For the language, select HTML, and for location, select ASP.NET MVC 2. For more information about how to use code snippets, see the Visual Studio documentation.

New RequireHttpsAttribute Action Filter

ASP.NET MVC 2 Preview 2 includes a new RequireHttpsAttribute class that can be applied to action methods and controllers. By default, the filter redirects non-SSL (HTTP) requests to the SSL-enabled (HTTPS) equivalent.

Overriding the HTTP Method Verb

When you build a Web site by using the REST architectural style, HTTP verbs are used to determine which action to perform for a resource. REST requires that applications support the full range of common HTTP verbs, such as GET, PUT, POST, and DELETE.

ASP.NET MVC includes attributes that you can apply to action methods and that enable ASP.NET MVC to select an action method based on the HTTP verb. In the following example, a POST request will call the first action method and a PUT request will call the second action method.

[HttpPost]

public ActionResult Edit(int id)

[HttpPut]

public ActionResult Edit(int id, Tag tag)

Because not all user agents support all HTTP verbs, a new HttpMethodOverride HTML helper method renders a hidden form input element that causes the form to appear to be a have been submitted with a different HTTP method from the one that was actually used. For example, browsers typically support only the GET and POST verbs in HTML forms. By using the HttpMethodOverride HTML helper method, you can have a form support PUT, DELETE, and other HTTP verbs.

The behavior of HttpMethodOverride affects the following attributes:

· HttpPostAttribute

· HttpPutAttribute

· HttpGetAttribute

· HttpDeleteAttribute

· AcceptVerbsAttribute

The HttpMethodOverride HTML helper method renders a hidden input element that has the name X-HTTP-Method-Override and the value set to the HTTP verb. The override value can also be specified in an HTTP header or in a query string value as a name/value pair.

The override is valid only for POST requests. The override values will be ignored for requests that use any other HTTP verb.

Single-Project Areas

ASP.NET MVC 2 Preview 2 includes support for single-project areas, which expands the existing support for multiple-project areas. The following figure shows the sample project layout for a single-project area.

clip_image002

For each area in the project, you must add a class that derives from AreaRegistration, and you must provide information about the area in the overridden members of that class, as shown in the following example:

namespace MyApplication.Areas.Blog {

public class Routes : AreaRegistration {

public override string AreaName {

get { return "blog"; }

}

public override void RegisterArea(AreaRegistrationContext context) {

context.MapRoute(

"blog_default",

"blog/{controller}/{action}/{id}",

new { controller = "Home", action = "Index", id = "" }

);

context.MapRoute(

"blog_whatsnew",

"whats-new",

new { controller = "Home", action = "WhatsNew", id = "" }

);

}

}

}

In the Global.asax code, add a call to the RegisterAllAreas method in order to register all areas. This method looks for all types that derive from the AreaRegistration class, instantiates the class, and then calls the RegisterArea method on the class. The following example shows how to do this.

public class MyMvcApplication : HttpApplication {

void App_Start() {

AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);

}

public static void RegisterRoutes(RouteCollection routes) {

routes.MapRoute("default", "{controller}/{action}/{id}", ...);

}

}

If you do not specify the namespace in the RegisterArea method by calling the context.Namespaces.Add method, the namespace of the registration class is used by default.

For more information, see Walkthrough: Creating an ASP.NET MVC Areas Application Using a Single Project on the MSDN Web site .

New HiddenInputAttribute for Templated Helpers

When the new HiddenInputAttribute class is applied to a property, the attribute indicates to the editor template whether a hidden input element should be rendered when editing the model. (The attribute sets an implicit UIHint value of HiddenInput). The DisplayValue property allows you to control whether the value is displayed in editor and display modes. When the attribute is set to false, nothing is displayed (not even the HTML markup that normally surrounds a field).

You might use this attribute in the following scenarios:

· When a view lets users edit the ID of an object and it is necessary to display the value as well as to provide a hidden input element that contains the old ID so that it can be passed back to the controller.

· When a view lets users edit a binary property that should never be displayed, such as a timestamp property. In that case, the value and surrounding HTML markup (such as the label and value) are not displayed.

The following example shows how to use the HiddenInputAttribute class.

public class ProductViewModel {

[HiddenInput] // equivalent to [HiddenInput(DisplayValue=true)]

public int Id { get; set; }

public string Name { get; set; }

[HiddenInput(DisplayValue=false)]

public byte[] TimeStamp { get; set; }

}

When the attribute is set to true (or no parameter is specified), the following occurs:

· In display templates, a label is rendered and the value is displayed to the user.

· In editor templates, a label is rendered and the value is rendered in a hidden input element.

When the attribute is set to false, the following occurs:

· In display templates, nothing is rendered for that field.

· In editor templates, no label is rendered and the value is rendered in a hidden input element.

Other Improvements

The following additional changes have been made to existing types and members for ASP.NET MVC 2 Preview 2.

· Removed the IsNullableValueType property from the TemplateInfo class and added it to ModelMetadata. When ASP.NET MVC looks up a template for Nullable<T>, the type of T is used for the type-based template lookup. This new property lets the template author know that the original value was a nullable type.

· Changed the Controller.Execute method to throw an exception when it is called more than once on the same instance. Controllers are meant to serve a single request and to be executed only once. Many developers were running into subtle bugs when they accidentally set an Inversion of Control (IoC) container to return a singleton instance of a controller rather than a new instance per request. This change makes the contract for controllers explicit.

· Changed templated helpers to return their output as a string rather than writing the output directly to the response. Before this change, the helpers returned an empty string and wrote their output directly to the response.

· Changed the Controller class so that it no longer inherits from MarshalByRefObject.

· Added support for the DataType.Password enumeration value for the DataTypeAttribute class. When a property is marked with this attribute, the default editor template will render a password input element.

· Made the AuthorizationContext(ControllerContext context) constructor obsolete. Instead, use the constructor that accepts both a ControllerContext parameter and an ActionDescriptor parameter.

· Made performance improvements to expression-based helper methods such as the template helpers. Helpers now cache compiled LINQ expressions.

· Added TemplateInfo.GetFullHtmlID and Html.GenerateIDFromName methods that are used to generate the recommended HTML id attribute value for an element within a template. This helps template authors make sure their templates work when they are nested in other templates.

· Added new attributes for simple REST scenarios, including HttpPutAttribute, HttpDeleteAttribute, and HttpGetAttribute. For more information, see Overriding the HTTP Method Override Verb earlier in this document.

· Changed the default editor template for nullable Boolean values to render a drop-down list that has three options: “Not Set”, “True”, and “False”. When “Not Set” is selected, the value that is submitted to the server is an empty string.

· Changed model types so that they can be either value types or reference types. This allows view pages and other types to support built-in .NET Framework value types such as System.DateTime and System.Int32.

· Changed the framework so that if a controller namespace is specified as part of a route registration (for example, by using the namespaces parameter in a call to the MapRoute method), the framework now looks in that namespace and its children for potential controller matches. For example, if the namespace MyNamespace is specified, the framework will look in the equivalent of MyNamespace.* for a matching controller.

· Renamed the htmlFieldPrefixId parameter for the template helper methods to htmlFieldPrefixName, and renamed TemplateInfo.GetFullHtmlFieldId renamed to TemplatInfo.GetFullHtmlFieldName. The new names better represent the purpose of the parameter and property.