Wednesday, August 20, 2014

Update ModelState for an individual Property in .NET MVC

As has been noted many times before, on postback MVC Helpers render the value stored in ModelState, not the values on the model.  Simon Ince describes this feature very well and recommends some solutions.

I have created a set of extension methods to allow easy update of an individual property value for postback if you find yourself in the need for this scenario.  These methods encapsulate the ModelState.Remove method but improve the use of this method by not requiring any magic string property names.

Here are the extension methods:

1 /// <summary>
2 /// Get the string equivalent of an instance property name using Reflection.
3 /// </summary>
4 /// <typeparam name="T">Any class type.</typeparam>
5 /// <typeparam name="TReturn">Any Property type for which a string translation is needed.</typeparam>
6 /// <param name="obj">A class instance.</param>
7 /// <param name="expression">Lambda expression describing the Property for which a string translation is needed.</param>
8 /// <returns>A string translation of a class Property member.</returns>
9 /// <remarks>http://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/</remarks>
10 public static string GetPropertyName<T, TReturn>(this T obj, Expression<Func<T, TReturn>> expression)
11 where T : class
12 {
13 MemberExpression body = (MemberExpression)expression.Body;
14 return body.Member.Name;
15 }
16
17 /// <summary>
18 /// Set the value of a Public property specified by an input string.
19 /// </summary>
20 /// <param name="input">Any object instance.</param>
21 /// <param name="propertyName">Name of a Public property for which the value is set.</param>
22 /// <param name="value">Object value to set.</param>
23 public static void SetValueByPropertyName(this object input, string propertyName, object value)
24 {
25 PropertyInfo prop = input.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
26 prop.SetValue(input, value);
27 }
28
29 /// <summary>
30 /// Updates the value of an individual property and resets the ModelState.
31 /// </summary>
32 /// <typeparam name="T">Any class type.</typeparam>
33 /// <typeparam name="TReturn"></typeparam>
34 /// <typeparam name="TReturn">Any Property type for which a string translation is needed.</typeparam>
35 /// <param name="model">A model class instance.</param>
36 /// <param name="expression">Lambda expression describing the Property for which a string translation is needed.</param>
37 /// <param name="updateValue">The new value to set on the model.</param>
38 public static void Update<T, TReturn>(this System.Web.Mvc.ModelStateDictionary modelState, T model, Expression<Func<T, TReturn>> expression, object updateValue)
39 where T : class
40 {
41 string propName = model.GetPropertyName(expression);
42 modelState.Remove(propName);
43 model.SetValueByPropertyName(propName, updateValue);
44 }
45

And here is an example implementation:


1 ModelState.Update(model, m => m.IsInitialPost, false);