模型绑定到ASP.NET MVC 3中的枚举

Che*_*hev 47 c# asp.net-mvc enums model-binding asp.net-mvc-3

我的控制器中有一个方法接受一个对象作为参数并返回一个JsonResult.此对象的一个​​属性是具有三个可能值的枚举.我假设当客户端为该属性传入一个int时,它将填充枚举,但它没有,它默认为0,枚举设置为第一个可能的选择.

有什么建议?

Che*_*hev 70

注意:这已在MVC 4中得到解决.如果升级到MVC 4对于您的项目来说是一个可行的选项,那么您只需要开始模型绑定到枚举.

也就是说,如果您仍然需要它,这里是MVC 3的解决方法.


问题在于MVC中的默认模型绑定器.正确的整数值使其成为模型绑定器,但绑定器未编码以映射到枚举的整数值.如果传入的值是包含枚举的命名值的字符串,它会正确绑定.这样做的问题是,当您使用该Json()方法将C#对象解析为JSON时,它会将整数值作为枚举值发送,而不是命名值.

最简单,最透明的解决方法是覆盖默认的模型绑定器并编写一些自定义逻辑来修复它绑定枚举的方式.

  1. 像这样创建一个新类.

    namespace CustomModelBinders
    {
        /// <summary>
        /// Override for DefaultModelBinder in order to implement fixes to its behavior.
        /// This model binder inherits from the default model binder. All this does is override the default one,
        /// check if the property is an enum, if so then use custom binding logic to correctly map the enum. If not,
        /// we simply invoke the base model binder (DefaultModelBinder) and let it continue binding as normal.
        /// </summary>
        public class EnumModelBinder : DefaultModelBinder
        {
            /// <summary>
            /// Fix for the default model binder's failure to decode enum types when binding to JSON.
            /// </summary>
            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)
  2. 然后只需将其注册到Global.asax文件中即可.

    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();
    
        AreaRegistration.RegisterAllAreas();
        RegisterRoutes(RouteTable.Routes);
    
        // Register your new model binder
        ModelBinders.Binders.DefaultBinder = new EnumModelBinder();
    }
    
    Run Code Online (Sandbox Code Playgroud)

而已.现在,枚举将正确绑定在JSON对象上.

http://www.codetunnel.com/how-to-bind-to-enums-on-json-objects-in-aspnet-mvc-3

  • 谢谢(你的)信息.非常令人失望地看到服务器到客户端的默认行为是Enum - > int,但是client-to-server是string - > Enum.好东西. (6认同)
  • 我想知道 - 从DefaultModelBinder继承或使用EnumModelBinder实现实现IModelBinder接口更好吗?Phil Haack在这里有一个例子:http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx我还没有完全实现IModelBinder枚举解决方案.我提出它是因为我需要一个Decimal活页夹(比如Haack的帖子),并且将类型特定的活页夹添加到ModelBinders.Binders集合(即:.Add(typeof(enum),EnumModelBinder); .Add(typeof( Decimal),DecimalModelBinder))而不是检查MyModelBinder中的每个类型 (5认同)

RPM*_*984 15

如何绑定到模型上的hook属性?

public class SomeModel
{
   public MyEnum EnumValue { get; set; }
   public int BindToThisGuy
   {
      get { return (int) EnumValue; }
      set { EnumValue = (MyEnum)value; }
   }
}
Run Code Online (Sandbox Code Playgroud)