5 Stimmen

ASP.Net MVC3 - warum scheitert die Standardunterstützung für das JSON-Modellbinding beim Dekodieren von Enum-Typen?

Ich habe ein Problem mit ASP.Net MVC3 (RC2). Ich stelle fest, dass die neue JSON-Model-Bindungsfunktion, die implizit in MVC3 enthalten ist, nicht in der Lage ist, in eine Eigenschaft zu deserialisieren, die einen Enum-Typ hat.

Hier ist eine Beispielklasse und ein Enum-Typ:

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

Betrachten Sie den folgenden Code, der den Unittest erfolgreich besteht:

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

Wenn ich obj1 oben serialisiere, aber dann diese Daten an einen MVC3-Controller (Beispiel unten) mit einem einzelnen Parameter vom Typ MyClass sende, werden alle anderen Eigenschaften des Objekts ordnungsgemäß deserialisiert, aber jede Eigenschaft, die ein Enum-Typ ist, wird auf den Standardwert (null) deserialisiert.

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

Ich habe den MVC-Quellcode von Codeplex heruntergeladen, aber ich stehe vor einem Rätsel, wo der tatsächliche Code für die Deserialisierung auftritt, was bedeutet, dass ich nicht herausfinden kann, was die Leute bei Microsoft verwendet haben, um die Deserialisierung durchzuführen, und somit feststellen kann, ob ich etwas falsch mache oder ob es einen Workaround gibt.

Über Vorschläge würde ich mich freuen.

9voto

Nathan Ridley Punkte 32508

Ich habe die Antwort gefunden. Ich hoffe, dass dies in MVC3 RTM behoben ist, aber im Grunde genommen passiert folgendes: Das Objekt wird intern über JsonValueProviderFactory korrekt deserialisiert, das JavaScriptSerializer verwendet, um die Arbeit zu erledigen. Es verwendet DeserializeObject(), damit es die Werte an den Standard-Modellbinder zurückgeben kann. Das Problem ist, dass der Standard-Modellbinder einen Integer-Wert nicht in ein Enum konvertiert/zuzuweisen wird, wenn der Eigenschaftstyp ein Enum ist.

Dazu gibt es eine Diskussion in den ASP.Net-Foren hier:
http://forums.asp.net/p/1622895/4180989.aspx

Die dort diskutierte Lösung besteht darin, den Standard-Modellbinder wie folgt zu überschreiben:

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);
    }
}

Dann fügen Sie in Application_Start die folgende Zeile hinzu:

ModelBinders.Binders.DefaultBinder = new EnumConverterModelBinder();

0voto

Darin Dimitrov Punkte 990883

Wie nennst du diese Aktion? Hast du es versucht:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X