LA.NET [EN]

Feb 18

Yesterday we’ve seen how we can  use the UpdateModel/TryUpdateModel to update an instance of an existing object with data that was sent back to the server during the current request. At the time, I’ve mentioned the ValueProviderResult class and promised a more detailed analysis of it in a future post. Since I like to keep my promises, today we’re going to look at the code of this class and see how it is used by the runtime.

ValueProviderResult instances are used internally when you want to automatically update the properties of an object with the values submitted on a postback. In other words, you’ll be using instances of this type whenever you use the binding operations for “recovering” objects from the values submitted on a request (if you don’t recall it, you’re able to do this with Bind attribute or by using the UpdateModel/TryUpdateModel methods). As we’ve seen yesterday, if you’re calling the UpdateModel/TryUpdateModel methods, you can  pass a dictionary of ValueProviderResult instances.Each entry of this entry of the dictionary is identified by a name (more about this on the next paragraphs).

If you look at the ValueProviderResult, you’ll see that it has three public properties: RawValue, AttemptedValue and Culture. RawValue points to an object which has the raw value of the object (this is the property used for updating the object’s property). AttemptedValue stores the new attempted value as a string (generally used for validation errors). Finally, there’s a CultureInfo object (Culture property) which is used when  converting value into a specific type. This will all make sense when we follow the normal usage of a ValueProviderResult instance.

Besides these properties, there is also the ConvertTo method (which has two overloads). This method is called by the default binder and is responsible for returning a value of the specified type (which, as you might expect,depends on the property and on the specified culture – remember the Culture property? ).

In practice,all the values of your properties are converted by instances of ValueProviderResult objects. For instance, if you recall yesterday’s example, we had a User class with two properties:

public class User {
    public Int32 UserId { get; set; }
    public String Name { get; set; }
}

Whenever you recover an instance of this type through binding, you need (at least) two ValueProviderResult instances: one for updating the value of the UserId property and another for updating the value of the Name property. But how are these instances created? If you’re not using the UpdateModel/TryUpdateModel overloads that receive the required dictionary of ValueProviderResult, then you’ll end up inheriting the one that is defined by the ControllerBase class (which is way at the top of the controller hierarchy you get when you reuse the default controller architecture).

This default dictionary is populated by using the current submitted values: for each entry, you’ll get a ValueProviderResult object identified by the that NameValueCollection entry key and filled with info recovered from that NameValueCollection entry. As I’ve said, the default binder is then able to use this dictionary for recovering the values that should be passed into the properties of the object you’re “recreating”.

You should take 2 points from this post:

  • if you’re not happy with getting all the values form the current request, then you can pass your own ValueProviderDictionary (ie, a custom ValueProviderResult which has the values you want) to the UpdateModel/TryUpdateModel methods (this is not possible when using the Bind attribute);
  • if you’re building a custom IModelBinder, then don’t forget to recover  the property value from an existing ValueProviderResult.

And that’s it for today. More on the MVC on the next posts.

1 comment so far

  1. Funka!
    10:07 pm - 6-5-2009

    I”d be curious to see an example of creating one”s own ValueProviderDictionary based on perhaps a filtered subset of the received FormCollection.

    I”ve discovered that the whitelisting and blacklisting features of UpdateModel do not seem to work very well when you are dealing with children objects and collections; for example, Company.Name, Company.Contacts[0].FirstName, etc., are hard to whitelist such that Company.IsActive and Company.Contacts[0].Status are not bound. Creating my own ValueProviderDictionary seems to be one possible solution…

    Thanks for the great article!