2011-01-03 5 views
5

Ho un problema con ASP.Net MVC3 (RC2). Sto scoprendo che la nuova funzionalità di bind del modello JSON, che è implicita in MVC3, non vuole deserializzare in una proprietà che ha un tipo enum.ASP.Net MVC3 - perché il supporto predefinito per l'associazione modello JSON non riesce a decodificare i tipi enum?

Ecco una lezione di prova e enum tipo:

public enum MyEnum { Nothing = 0, SomeValue = 5 } 
public class MyClass 
{ 
    public MyEnum Value { get; set; } 
    public string OtherValue { get; set; } 
} 

Si consideri il seguente codice, che passa con successo il test di unità:

[TestMethod] 
public void Test() 
{ 
    var jss = new JavaScriptSerializer(); 
    var obj1 = new MyClass { Value = MyEnum.SomeValue }; 
    var json = jss.Serialize(obj1); 
    var obj2 = jss.Deserialize<MyClass>(json); 
    Assert.AreEqual(obj1.Value, obj2.Value); 
} 

Se ho serializzare obj1 sopra, ma poi inviare i dati per un controller MVC3 (esempio sotto) con un singolo parametro di tipo MyClass, qualsiasi altra proprietà dell'oggetto deserializza correttamente, ma qualsiasi proprietà che è un tipo enum deserializza al valore predefinito (zero).

[HttpPost] 
public ActionResult TestAction(MyClass data) 
{ 
    return Content(data.Value.ToString()); // displays "Nothing" 
} 

Ho scaricato il codice sorgente MVC da CodePlex ma stumped quanto a dove si verifica il codice vero e eseguire la deserializzazione, il che significa che non riesco a capire cosa la gente di Microsoft hanno utilizzato per eseguire la deserializzazione e quindi determinare se sto facendo qualcosa di sbagliato o se c'è una soluzione alternativa.

Qualsiasi suggerimento sarebbe apprezzato.

+0

Ho aggiunto una risposta su questo thread che potrebbe aiutare. http://stackoverflow.com/questions/6051756/model-binding-to-enums-in-asp-net-mvc-3/9070963#9070963 – Difinity

risposta

9

Ho trovato la risposta. Spero che questo sia corretto in MVC3 RTM, ma essenzialmente ciò che accade è che l'oggetto deserializza correttamente internamente tramite JsonValueProviderFactory, che usa JavaScriptSerializer per eseguire il lavoro. Utilizza DeserializeObject() in modo che possa trasferire nuovamente i valori al raccoglitore modello predefinito. Il problema è che il raccoglitore modello predefinito non converte/assegna un valore int quando il tipo di proprietà è un enum.

C'è una discussione di questo al forum di ASP.Net qui:
http://forums.asp.net/p/1622895/4180989.aspx

La soluzione discusso c'è da sovrascrivere il legante modello predefinito in questo modo:

public class EnumConverterModelBinder : DefaultModelBinder 
{ 
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) 
    { 
     var propertyType = propertyDescriptor.PropertyType; 
     if(propertyType.IsEnum) 
     { 
      var providerValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
      if(null != providerValue) 
      { 
       var value = providerValue.RawValue; 
       if(null != value) 
       { 
        var valueType = value.GetType(); 
        if(!valueType.IsEnum) 
        { 
         return Enum.ToObject(propertyType, value); 
        } 
       } 
      } 
     } 
     return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder); 
    } 
} 

Poi, nel Application_Start, aggiungere la seguente riga:

ModelBinders.Binders.DefaultBinder = new EnumConverterModelBinder(); 
+0

Questo problema verrà risolto nella prossima versione di ASP.NET MVC. – marcind

0

Come stai chiamando questa azione? Hai provato:

$.post(
    '/TestAction', 
    JSON.stringify({ OtherValue : 'foo', Value: 5 }), 
    function(result) { 
     alert('ok'); 
    } 
); 
+0

Non lo chiamo da una pagina Web, I lo sto chiamando da un'altra applicazione tramite 'WebClient.UploadString()'. Il processo di post funziona davvero, sono solo le proprietà enum della classe che non deserializzano. Tutte le altre proprietà si incontrano perfettamente. –

+0

@Nathan, potresti mostrare il codice chiamante? –

+0

Ho trovato il problema; la classe DefaultModelBinder non converte inti in Enums. http://forums.asp.net/p/1622895/4180989.aspx –

Problemi correlati