Value Providers
Value Providers are the data sources that feeds data to models. At the time of model binding the Model Binders interacts with Value Providers to fill the models with data.
The framework contains a bunch of built-in value providers like FormValueProvider,
RouteDataValueProvider, QueryStringValueProvider, and
HttpFileCollectionValueProvider
that fetches data from Request.Form, Request.QueryString,
Request.Files, and RouteData.Values. These Value Providers are called in the order they are
registered and so the one that registered earlier gets the first chance. We can easily restrict the model to bind with data from a particular Value Provider.
The interesting thing is we can even create own custom Value Provider to feed data to models. In this article we see how to create a value provider that feeds data from the session.
Custom Session Value Provider
All the built-in value providers implements the interface IValueProvider.
public interface IValueProvider
{
bool ContainsPrefix(string prefix);
ValueProviderResult GetValue(string key);
}
The ContainsPrefix method should return true if the value provider can provide value for that property name. The
GetValue method returns the
actual value for the property wrapped as ValueProviderResult.
So here is our custom session value provider, quite simple!
public class SessionValueProvider: IValueProvider
{
public bool ContainsPrefix(string prefix)
{
return HttpContext.Current.Session[prefix] != null;
}
public ValueProviderResult GetValue(string key)
{
return new ValueProviderResult(HttpContext.Current.Session[key],
HttpContext.Current.Session[key].ToString(), CultureInfo.CurrentCulture);
}
}
How we can use our SessionValueProvider? The answer is we need a factory for that.
public class SessionValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider
(ControllerContext controllerContext)
{
return new SessionValueProvider();
}
}
Now all we have to do is register the factory in Global.asax.cs.
ValueProviderFactories.Factories.Add(new SessionValueProviderFactory());
If you have a model like,
public class UserModel
{
public string AccountNo { get; set; }
...
}
and an action that expects this model,
public ViewResult SomeAction(UserModel userModel, )
{
...
}
Also if you have the AccountNo stored in session as,
Session["AccountNo"] = "X8w237jd923"
Our SessionValueProvider fills the userModel.AccountNo with the value from the session. Isn't that cool? Yes it is.
The SessionValueProvider even helps us to avoid the dependency between Session in controller actions and that simplifies the unit testing.
You can even think about value providers that feeds data to models from configuration or other strange places.
History
- 9/10/2012 - Creating the ValueProviderResult in GetValue() method in SessionValueProvider is modified to pass both the raw and modified values.