ASP.Net MVC3 - 为什么JSON模型绑定的默认支持无法解码为枚举类型?

Nat*_*ley 5 json asp.net-mvc-3

我遇到ASP.Net MVC3(RC2)的问题.我发现新的JSON模型绑定功能(隐含在MVC3中)不希望反序列化为具有枚举类型的属性.

这是一个示例类和枚举类型:

public enum MyEnum { Nothing = 0, SomeValue = 5 }
public class MyClass
{
    public MyEnum Value { get; set; }
    public string OtherValue { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

请考虑以下代码,它成功通过了单元测试:

[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);
}
Run Code Online (Sandbox Code Playgroud)

如果我obj1在上面序列化,然后使用MyClass类型的单个参数将该数据发布到MVC3控制器(下面的示例),则对象的任何其他属性都会正确反序列化,但任何枚举类型的属性都会反序列化为默认值(零)值.

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

我已经从codeplex下载了MVC源代码,但是我很难理解执行反序列化的实际代码在哪里发生,这意味着我无法弄清楚Microsoft的人们已经用来执行反序列化,从而确定我是否做错了什么或是否有解决方法.

任何建议,将不胜感激.

Nat*_*ley 9

我找到了答案.我希望这在MVC3 RTM中得到修复,但实质上发生的是对象在内部通过正确反序列化JsonValueProviderFactory,JavaScriptSerializer用于完成工作.它使用DeserializeObject()它可以将值传递回默认的模型绑定器.问题是当属性类型是枚举时,默认模型绑定器不会转换/赋值int值.

ASP.Net论坛对此进行了讨论:http:
//forums.asp.net/p/1622895/4180989.aspx

讨论的解决方案是覆盖默认的模型绑定器,如下所示:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后Application_Start,添加以下行:

ModelBinders.Binders.DefaultBinder = new EnumConverterModelBinder();
Run Code Online (Sandbox Code Playgroud)