Localized enums with Entity Framework Code-First 4.1 in WPF MVVM and ASP.NET MVC 3. Part 3)

By Mirek on (tags: ASP.NET MVC, Code First, Entity Framework, enums, lozalization, mvvm, WPF, categories: code)

Part 3. Displaying and binding localized names of enum values
in ASP.NET MVC 3 application

To display localized enums in ASP.NET MVC 3 application we use custom description attribute described in Part 2) and extension method to get the description for each enum value. The type converter is not useful here so we need another approach to achieve the goal.

Let’s generate the editing View for our Client object, where we want to have an text box for name and drop down list with preselected client’s Status and all possible values of Status type.

   1: <h2>Edit @Model.Name </h2>
   2:  
   3: @using (Html.BeginForm()) {
   4:     @Html.ValidationSummary(true)
   5:     <fieldset>
   6:         <legend>ChatClient</legend>
   7:  
   8:         @Html.HiddenFor(model => model.Id)
   9:  
  10:         <div class="editor-label">
  11:             @Html.LabelFor(model => model.Name)
  12:         </div>
  13:         <div class="editor-field">
  14:             @Html.EditorFor(model => model.Name)
  15:             @Html.ValidationMessageFor(model => model.Name)
  16:         </div>
  17:  
  18:         <div class="editor-label">
  19:             @Html.LabelFor(model => model.Status)
  20:         </div>
  21:         <div class="editor-field">
  22:             @Html.DropDownListFor(model => model.Status,Model.Status.ToSelectList())
  23:             @Html.ValidationMessageFor(model => model.Status)
  24:         </div>
  25:  
  26:         <p>
  27:             <input type="submit" value="Save" />
  28:         </p>
  29:     </fieldset>
  30: }

You can see hare an extension method ToSelectList() which looks following

   1: public static IEnumerable<SelectListItem> ToSelectList(this Enum enumValue, bool selectMe = true)
   2:         {
   3:             return (from Enum e in Enum.GetValues(enumValue.GetType())
   4:                     select new SelectListItem
   5:                     {
   6:                         Selected = (selectMe && e.Equals(enumValue)),
   7:                         Text = e.GetDescription(),
   8:                         Value = e.ToString()
   9:                     }).ToList();
  10:         }

It returns the list of SelectListItem with all values of enum type localized to current culture. Parameter selectMe indicates if current enum value has to be selected on the list.
Using this list in drop down generates html similar to following

   1: <select id="Status" ><option value="Online">Online</option>
   2: <option value="Busy">Besetzt</option>
   3: <option selected="selected" value="Away">Weg</option>
   4: <option value="Offline">Offline</option>
   5: </select>
     

Generally that could be enough to use localized enums in ASP.NET MVC 3. Values are properly localized, displayed and submitting the form generates properly filled Client model. Unfortunatelly the version of MVC 3 framework I had used had a bug which caused that html representation of enum value was not properly recognized and translated to enum type and submiting form produces error like on the following screen.

screen1

Underlying value Busy has not been recognized as enum type value.

As a solution for that I have used a custom model binder found on ASP.NET forums here, which after small modification works for my case. Just add following class

   1: public class EnumConverterModelBinder : DefaultModelBinder
   2: {
   3:     protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext,
   4:         PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
   5:     {
   6:         var propertyType = propertyDescriptor.PropertyType;
   7:         if (propertyType.IsEnum)
   8:         {
   9:             var providerValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
  10:             if (null != providerValue)
  11:             {
  12:                 var value = providerValue.RawValue;
  13:                 if (null != value)
  14:                 {
  15:                     var valueType = value.GetType();
  16:                     if (!valueType.IsEnum)
  17:                     {
  18:                         return Enum.Parse(propertyType, ((string[])value)[0]);
  19:                     }
  20:                 }
  21:             }
  22:         }
  23:         return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
  24:     }
  25: }

and to use this binder add following line in Global.asax file of MVC 3 application

   1: protected void Application_Start()
   2: {
   3:     ModelBinders.Binders.DefaultBinder = new EnumConverterModelBinder();
   4: }

These treatments are no longer needed in latest version of ASP.NET-MVC-3-Tools-Update-RTM framework, but I could not find out how to update my mvc 3 project to make the binding enums working. I also tried using an ASP.NET MVC 3 Application Updater available here, but it did not fix the problem, so the only solution was to use a custom model binder for binding enum values.