Published: 08 Dec 2010
By: Xianzhong Zhu

In the last article, we've mainly discussed the new-styled DI support in ASP.NET MVC 3 Beta/RC in relation to the two new services - IControllerActivator and IViewPageActivator. Obviously, both of them are connected with controllers and views. In this article, however, we will shift our attention to the Model (generally called viewmodal in many blogs) related DI manipulations.

Contents [hide]

The Experience ASP.NET MVC 3 Beta series

  • Part 1 In the coming ASP.NET MVC 3.0 a lot of new good things will be added or enhanced. In this article, we are going to focus upon the new view engine Razor to see how it will simplify the view design.
  • Part 2 In addition to the introduction of a new view engine Razor, ASP.NET MVC 3 Beta has also introduced numerous new HtmlHelpers, such as Chart, Crypto, WebGrid, WebImage, WebMail, etc. This article aims to introduce the two commonly-used new helper controls – WebGrid and Chart using relevant examples.
  • Part 3 In this installment, I'll first tell you a short story about unobtrusive JavaScript. Then, we'll delve into the unobtrusive client-side validation support. Finally, we will research into a more interesting story - the unobtrusive jQuery-Based Ajax support.
  • Part 4 In this article, we are going to continue to explore the other three important helpers - WebImage, WebMail, and Crypto.
  • Part 5 Starting from this article, let's explore some more advanced concepts and related utilizations associated with flexible Dependency Injection support introduced in ASP.NET MVC 3 Beta.
  • Part 6 In the last article, we've mainly discussed the new-styled DI support in ASP.NET MVC 3 Beta/RC in relation to the two new services - IControllerActivator and IViewPageActivator. Obviously, both of them are connected with controllers and views. In this article, however, we will shift our attention to the Model (generally called viewmodal in many blogs) related DI manipulations.
  • Part 7 Since ASP.NET MVC 1, CSRF (Cross Site Request Forgery) has been considered by introducing a set of anti-forgery helpers. In this article, we are to detail into CSRF related concepts and ASP.NET MVC's helper functions again CSRF.
  • Part 8 In this series of articles, we are going to explore as many as possible aspects of cache programming in the latest ASP.NET MVC 3 RC2 framework. And also, all the related samples have been tested against the latest ASP.NET MVC 3 RC 2.
  • Part 9 In the first part of this series, we've mainly explored Output Cache related issues. In this second part, however, we are going to delve into the general Data Cache topic.
  • Introduction

    In the last article, we've mainly discussed the new-styled DI support in ASP.NET MVC 3 Beta/RC in relation to the two new services – IControllerActivator and IViewPageActivator. Obviously, both of them are connected with controllers and views. In this article, however, we will shift our attention to the Model (generally called viewmodal in many blogs) related DI manipulations. In detail, we are going to explore four existing services (Model validation providers, Model metadata provider, Value providers, and Model binders) in ASP.NET MVC 3 Beta/RC using the new dependency resolver tools through related examples.

    By the way, as in the last article "Experience ASP.NET MVC 3 Beta/RC -the New Dependency Injection Support - Part 1", although all the sample applications are developed using MVC 3 Beta they are also available in the latest RC version.

    NOTE

    The development environments we'll utilize in the sample application are:

    1. Windows XP Professional (SP3);

    2. .NET 4.0;

    3. Visual Studio 2010;

    4. ASP.NET MVC 3 Beta (http://www.microsoft.com/downloads/en/details.aspx?FamilyID=0abac7a3-b302-4644-bd43-febf300b2c51);

    5. Microsoft Unity 2.0.

    New Dependency Resolver Support for Existing Model-related Services

    ASP.NET MVC 3 Beta/RC provides dependency resolvers support for the following existing model related services:

    • Model metadata provider. A single class that implements ModelMetadataProvider can be registered in the dependency resolver, and the system will use it to provide metadata for the templating and validation systems.
    • Model binders. Classes that implement IModelBinderProvider can be registered in the dependency resolver, and the system will use them to create model binders that are consumed by the model binding system.
    • Model validation providers. Classes that implement ModelValidatorProvider can be registered in the dependency resolver, and the system will use them to support client- and server-side validation.
    • Value providers. Classes that implement ValueProviderFactory can be registered in the dependency resolver, and the system will use them to create value providers that are consumed by the controller and during model binding.

    Starting from next section, we are going to introduce how dependency resolvers help to more easily implement the above four services. But, before the real story begins, let's build up a sample project sketch using ASP.NET MVC 3 Beta.

    Set up Sample Application Sketch

    First of all, let's set up a sample application sketch using ASP.NET MVC 3 Beta. Again, you can also download and install the latest ASP.NET MVC 3 Release Candidate to test all these samples in this series.

    Start up Visual Studio 2010, select the "ASP.NET MVC 3 Web Application" template, and then select the project template "Internet Application" and Razor view engine to create a project named MVC3PPPB.

    New Support for Model Metadata Provider

    In this section, we are to examine the MVC 3's new support for the model metadata related stuffs. First, let's retrospect the built-in metadata support in ASP.NET MVC.

    Built-in metadata support

    ASP.NET MVC provides the ability to create metadata about the data model. And further, metadata can be used to perform various tasks, such as validation and special rendering. Listing 1 illustrates the LogOnModel model definition automatically generated by Visual Studio 2010.

    Listing 1: The LogOnModel model definition with built-in metadata

    Above, the attribute (namely the metadata) Required is used to specify the related properties on the data model class LogOnModel are required, while another attribute Display specifies what the related properties' display names on the client side are. And further, the third attribute DataType specifies the name of an additional type (in this case referring to the enum type DataType.Password) to associate with the data field Password.

    Table 1 shows a complete list of validation attributes from the assembly System.ComponentModel.DataAnnotations.

    Table 1: Built-in validation attributes from the Annotations assembly

    Attribute

    Description

    StringLength

    Specifies the maximum length of the string allowed in the data field.

    Required

    Specifies that a data field value is required.

    RegularExpression

    Specifies that a data field value must match the specified regular expression.

    Range

    Specifies the numeric range constraints for the value of a data field.

    DataType

    Specifies the name of an additional type to associate with a data field (one of the DataType enumerated values, like EmailAddress, Url or Password).

    Note, by default, the ModelMetadataProviders class sets the class DataAnnotationsModelMetadataProvider as the default metadata provider for the ASP.NET MVC framework. Typically, we do not have to use this class directly. If we want to develop a custom attribute-based metadata provider, we can select it as one of the solutions – just need to inherit from this class.

    For brevity, we are not to detail into the .NET Data Annotations and the MVC built-in metadata options, but leave spaces to the really interesting things.

    Writing a custom model metadata provider

    As with most of ASP.NET MVC's core mechanisms, the model metadata system is completely pluggable. The framework includes a comprehensive implementation, but also allows you to extend or completely replace it if you wish. Figure 1 shows how this extensibility architecture.

    Figure 1: ASP.NET MVC’s extensible architecture for model metadata

    ASP.NET MVC’s extensible architecture for model metadata

    If the built-in data annotations attributes and DataAnnotationsModelMetadataProvider don't satisfy your needs, you can create a custom metadata provider by creating a class that inherits from one of the following base classes:

    • ModelMetadataProvider: The abstract base class for all metadata providers.
    • AssociatedMetadataProvider: Usually a better choice of base class for a custom metadata provider. It deals with much of the tricky work related to obtaining the list of attributes associated with each model property, and transparently fetches these attributes from "buddy" classes configured via [MetadataType]. All you have to do is override a single method, CreateMetadata, and return a ModelMetadata instance based on a supplied set of attributes, a model type, a property name, and so on.
    • DataAnnotationsModelMetadataProvider: The default metadata provider. By inheriting from this, you can retain support for standard System.ComponentModel Data Annotation attributes. Again, you only need to override its CreateMetadata method.

    For a more intuitive understanding with the class inheritance hierarchy, you can refer to the diagram given in Figure 2.

    Figure 2: Custom Model Metadata Provider and related inheritance relationship

    Custom Model Metadata Provider and related inheritance relationship

    It's worth noticing that in ASP.NET MVC 3, the metadata providers have been made findable via the newly-introduced dependency resolver.

    Moreover, the logic in ModelMetadataProviders has been updated to attempt to find the implementation of ModelMetadataProvider first by calling DependencyResolver.GetService(typeof(ModelMetadataProvider)). If the service does not exist in the dependency resolver, then it falls back to the static registration point. If you register a model metadata provider in both the static registration point and in the dependency resolver, MVC will throw an exception.

    In the subsequent paragraphs, we are going to write a custom metadata provider to enhance the default one, so that it recognizes some extra naming conventions.

    1. Model definition

    For simple test, we can define the model class as shown below:

    Listing 2: Define the model

    Here, we define a property Id, and several X-suffixed ones. Our aim is to achieve the result that, in the final CreateNewContact.cshtml view page, the Id field becomes invisible, while the value of the other X-suffixed ones must be provided and the display names are shown without the X suffix.

    Next, let's look at the custom metadata provider.

    2. Write the custom metadata provider

    Since the default DataAnnotationsModelMetadataProvider cannot satisfy our need, we'd better construct our own custom metadata provider, as shown below.

    Listing 3: Custom metadata provider

    As implied previously, it's simpler to create a custom metadata provider that inherits from the AssociatedMetadataProvider class. In this case, we just need to override the only method CreateMetadata. Here, the way to create the ModelMetadata instance is easy to follow up; the later filter manipulations are also not difficult to understand. All revolves around the above-mentioned purpose.

    3. Hooking it up

    The last thing you need to do to hook it up is set the new CustomModelMetadataProvider as the current ModelMetadataProvider; this is done within the Application_Start method in the file Global.asax.cs.

    Listing 4: The static way to register the custom metadata provider

    Note ModelMetadataProvider is a "singly registered" style service since ASPNNET MVC 2. The static registration point for this service is at ModelMetdataProviders.Current (as illustrated above) for non-DI users.

    In fact, we can of course select the dynamic mode to accomplish the above registration, as shown below.

    Listing 5: The dynamic way to register the custom metadata provider

    Since the last article has explained the above related stuffs, we don't need to waste space any more.

    4. Create a test controller action and related view

    The two required actions are as follows:

    They are simple enough – just a common implementation.

    The related View is shown below:

    Next, let's run the sample above using the url http://localhost:portnumber/contacts/CreateNewContact to see what will happen. Figure 3 shows you the final result.

    Figure 3: The custom metadata provider related sample in action

    The custom metadata provider related sample in action

    First, note that the Id field has been hidden, while the rest ones related X-suffix has also got filtered. Next, let's click the menu item "View-Page Source" (I used Firefox here) to see what happened behind the scene. Figure 4 gives the related contents.

    Figure 4: The custom metadata provider in action

    The custom metadata provider in action

    Please notice the underlined contents in the above figure.

    New Support for Model Binder

    Starting from this section, we are to examine the MVC 3's new support for the model binder related stuffs. First, let's, as usual, look back upon the built-in model binder support in ASP.NET MVC.

    Built-in model binder support

    Each time the client-side users submit an HTML form, your application receives an HTTP request containing the form's data as a set of name/value pairs. You can manually pick out each data item that you wish to receive, but this is labor intensive, especially when plenty of data require to be dealt with.

    Model binding is ASP.NET MVC's mechanism for mapping HTTP request data directly into action method parameters and custom .NET objects. As you'd expect, ASP.NET MVC defines some ready-to-use naming conventions to let you quickly map complex data structures without having to specify all the mapping rules manually.

    Herein, we are not going to delve into the built-in model binding story. But, to gain a general idea of what the built-in support does for us is still necessary. In detail, we can, in the current ASP.NET MVC application achieve model bind to the following:

    • Action method parameters
    • Custom types
    • Arrays, Collections, and Dictionaries
    • Collections of custom types

    In addition, when doing model binding, you can also specify a custom prefix, omit some prefix, select a subset of properties to bind, invoke model binding directly, and even more...

    Next, let's look at how to write a custom model binder and how MVC 3 provides related new support.

    Writing a custom model binder

    As usual, let's first define a simple model, just for test's purpose.

    1. Define Model

    Next, let's create the custom model binder.

    2. Define a custom model binder

    There are typically two means in ASP.NET MVC to create a custom model binder: one is to inherit from the MVC 3 newly-introduced interface IModelBinderProvider; the other is to derive from the class DefaultModelBinder. With the new interface IModelBinderProvider, developers can dynamically implement IModelBinder.

    In this case, we utilize the former.

    Listing 6: GenericModelBinderProvider.cs

    To achieve the aim of loose couple, we first created a utility class from the generic class IModelBinder<Person>. Note the generic parameter is just the model defined previously. And then, we created a custom model binder inherited from IModelBinderProvider. As is seen, the only thing to do is to implement the method GetBinder, in which we dealt with the preceding tool PersonModelBinder and invoked the class DependencyResolver associated member to return the binder.

    3. Register the custom model binder

    As the above samples, we can select both the static mode and dynamic one to perform the model binder binding.

    (1) Static mode:

    (2) Dynamic mode:

    For detail, please refer to the explanation given above.

    4. Define action method and related test view

    Add a new action named CustomTypesModelBindingTest in the Home controller:

    Here, we used the custom model class Person as the parameter.

    Next, right click the action CustomTypesModelBindingTest to create a related view page:

    As we've seen, when we click the button "Submit" the small form related fields will be submitted to the server side and another related action RegisterPerson will be invoked. As a result of this, the value of the DateOfBirth property will be rendered on a new page (sorry for my not having provided the better Ajax-styled solution; please add it yourselves).

    New Support for Validator Provider

    Since ASP.NET MVC 2, an extensible model validation system has been introduced, in order that developers can implement a custom class derived from ModelValidatorProvider. And also, the support can influence the validation process on both the client side and server side.

    Moreover, please note these above validator providers in ASP.NET MVC 3 have also become findable via the dependency resolver.

    To write a validation provider, what you need to do is derive a new class from the abstract class ModelValidationProvider and implement its single method GetValidators:

    The usage is relatively straight forward: given a controller context (which describes the current request) and a ModelMetadata (which describes the object to be validated), you should return 0 or more validators to be run against the model.

    In fact, a good way to explore the means of overriding the method GetValidators is to pick up .NET Reflector to research into some existing model validator providers, such as EmptyModelValidatorProvider and ClientDataTypeModelValidatorProvider. Here, we are to omit the related discussion.

    Next, let's also create a simple custom model validator provider to get a better idea of the related concepts.

    Create a custom Model Validator

    In detail, a validator is a class derived from the abstract class ModelValidator. This class accepts the instances of ModelMetadata and ControllerContext as its constructor arguments, and exposes them via protected properties.

    Writers of custom validators have to implement to method Validate to do the server-side validation. And alternatively, they may override the virtual method GetClientValidationRules to provide client-side validation.

    Before rolling up our sleeves, let's first take a look at the inheritance hierarchical relationships associated with validation, as shown in Figure 5 below.

    Figure 5: Inheritance hierarchy concerning validation classes

    Inheritance hierarchy concerning validation classes

    As you've guessed, we select to inherit from the class AssociatedValidatorProvider to create our simple custom model validator.

    1. Create the custom Validator Provider and ModelValidator

    Here's the related code.

    As indicated above, only the properties with a X suffix will be validated. Next, let's look at the model definition.

    2. Model Definition

    Here's the simple model class Product related code.

    Note above we've commented out all common validation rules.

    3. Register the custom Validator Provider

    Now, it's time to register the custom validator provider. This is still implemented in the Application_Start method of the file Global.asax.cs. And also, there are two basic ideas to do the registration: static and dynamic.

    Till now, I think, there should be nothing strange to you in understanding the above code.

    4. Create test action method

    Now, let's create an action Index to execute the above invalidate test. And, as usual, another related action named Index is used for HTTP post test.

    5. Set up the test view page

    The last step is right click the above action to create a strong-typed view page named Index to do the test.

    What appear above are the commonly-seen HTML validation helpers.

    Now, start up the above sample and navigate to the url http://localhost:portnumber/product/index, then a initial product edit form turns up. If leaving all fields empty and click the button 'Save', then you will notice a running-time result as given in Figure 6 below.

    Figure 6: Using custom validator in ASP.NET MVC

    Using custom validator in ASP.NET MVC

    As pointed out before, only those fields ended with the suffix X will generate the related error prompt info.

    New Value Provider Support

    In this section, let's, as usual, first look back upon the inbuilt value provider support. Then, we'll construct a custom value provider using the new MVC 3 related support.

    Built-in Value Provider in ASP.NET MVC

    Value Providers are the mechanism within the MVC framework that tries to take information from the HTTP Request and then resolve parameter values on action methods. In conclusion, whether complex or simple types, they will all be resolved using one of the four inbuilt value providers listed below.

    • FormValueProvider: Provides values from posted form parameters.
    • QueryStringValueProvider: Provides values from the query string collection.
    • HttpFileCollectionValueProvider: Provides values from posted files.
    • RouteDataValueProvider: Provides values from route parameters.

    ASP.NET MVC 2 introduced a new method to find value providers - the ValueProviderFactory class. And, in ASP.NET MVC 3, the ValueProviderFactory instances have also made findable via the newly-introduced dependency resolver.

    Next, we are going to create a custom value provider to look at what happens behind the scene.

    Create a Custom Value Provider

    To create a custom value provider, it isn't enough just to implement IValueProvider. You must also create a factory class (inherited from ValueProviderFactory) so the framework can create a separate instance of your value provider for each HTTP request.

    Listing 22 below illustrates the source code of the ValueProviderFactory class.

    Obviously, what we need to do is override the only method GetValueProvider to return an instance of IValueProvider. And indirectly, we have to implement the interface IValueProvider related two members.

    Next, let's start the real work from the model definition.

    1. Define model

    Above, we provided the common data connotations to achieve the server-side validation.

    2. Define the custom value provider

    As is seen, the real work is around the internal class PriceValueProvider which implements the interface IValueProvider. By looking more closely, you will note that herein we are only interested in the field with a prefix "Price" – method ContainsPrefix finishes this job. Next, another method is responsible to retrieve a value object using the specified key. Finally, by overriding the method GetValueProvider, the custom value provider will be returned.

    3. Register the custom value provider

    It's very important that, according to my test, in this case we can only use the static service – the dynamic mode to register will result in no result!!!

    The detailed related explanation has already given in the preceding sections, so we are to omit the similar restatement. Next, let's also construct an action to do the related test.

    4. Create test action method

    5. Create test view page – Index2.cshtml

    Now, let's start up the above sample and enter the url http://localhost:portnumber/product/index2. And then, populate some data. Note in the 'Price' field we fill in the number 123,345. Without the above custom value provider support, when you click the button "Save" you will see an error message "The value '123,345' is not valid for Price". Using our custom value provider, when you click the button "Save" we will see it changes to "123345", i.e. accepted by the server side. Figure 7 below shows the case using our custom value provider (two snapshots merged).

    Figure 7: The custom value provider in action

    The custom value provider in action

    By the way, for the cookie related custom value provider, you can refer to a good blog at http://www.dotnetguy.co.uk/post/2010/03/07/ASPNET-MVC-working-smart-with-cookies-e28093-Custom-ValueProvider.aspx.

    Summary

    In this article, we've explored the four important existing services, i.e. model metadata provider, model binders, model validation providers, value providers, related new support in ASP.NET MVC 3. In detail, we created four related custom services. During the course, we learned the early static registration mode and especially the dynamic mode via the newly-introduced dependency resolver. As said at the beginning of this article, almost anything can be extended using DI in ASP.NET MVC 3, which opens many too opportunities to developers. One last word is the techniques explained in this article are still around a pre-release version - specific technical details may change before the final release of ASP.NET MVC 3. So, just for your reference.

    The Experience ASP.NET MVC 3 Beta series

  • Part 1 In the coming ASP.NET MVC 3.0 a lot of new good things will be added or enhanced. In this article, we are going to focus upon the new view engine Razor to see how it will simplify the view design.
  • Part 2 In addition to the introduction of a new view engine Razor, ASP.NET MVC 3 Beta has also introduced numerous new HtmlHelpers, such as Chart, Crypto, WebGrid, WebImage, WebMail, etc. This article aims to introduce the two commonly-used new helper controls – WebGrid and Chart using relevant examples.
  • Part 3 In this installment, I'll first tell you a short story about unobtrusive JavaScript. Then, we'll delve into the unobtrusive client-side validation support. Finally, we will research into a more interesting story - the unobtrusive jQuery-Based Ajax support.
  • Part 4 In this article, we are going to continue to explore the other three important helpers - WebImage, WebMail, and Crypto.
  • Part 5 Starting from this article, let's explore some more advanced concepts and related utilizations associated with flexible Dependency Injection support introduced in ASP.NET MVC 3 Beta.
  • Part 6 In the last article, we've mainly discussed the new-styled DI support in ASP.NET MVC 3 Beta/RC in relation to the two new services - IControllerActivator and IViewPageActivator. Obviously, both of them are connected with controllers and views. In this article, however, we will shift our attention to the Model (generally called viewmodal in many blogs) related DI manipulations.
  • Part 7 Since ASP.NET MVC 1, CSRF (Cross Site Request Forgery) has been considered by introducing a set of anti-forgery helpers. In this article, we are to detail into CSRF related concepts and ASP.NET MVC's helper functions again CSRF.
  • Part 8 In this series of articles, we are going to explore as many as possible aspects of cache programming in the latest ASP.NET MVC 3 RC2 framework. And also, all the related samples have been tested against the latest ASP.NET MVC 3 RC 2.
  • Part 9 In the first part of this series, we've mainly explored Output Cache related issues. In this second part, however, we are going to delve into the general Data Cache topic.
  • <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Xianzhong Zhu

    I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...

    This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
    A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
    jQuery Mobile ListView
    In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
    Exception Handling and .Net (A practical approach)
    Error Handling has always been crucial for an application in a number of ways. It may affect the exe...
    JQuery Mobile Widgets Overview
    An overview of widgets in jQuery Mobile.
    Book Review: SignalR: Real-time Application Development
    A book review of SignalR by Simone.

    You might also be interested in the following related blog posts


    Telerik Announces Support for Microsoft Silverlight 3 read more
    Framework Design Guidelines: Dependency Properties read more
    Using Assert.AreSame read more
    DataTable JSON Serialization in JSON.NET and JavaScriptSerializer read more
    Popfly beta read more
    IIS/ASP.NET Settings and Virtual Directory Inheritance read more
    ASP.NET AJAX 1.0 Beta 2 Release read more
    IBM Message Service Client for .NET read more
    Eureka! read more
    Supportable Customizations: Don't Panic read more
    Top
     
     
     

    Discussion


    Subject Author Date
    placeholder It's Not Support Chinese Wang Kai 2/17/2011 12:28 AM

    Please login to rate or to leave a comment.