在ASP.NET MVC 3中绑定到枚举的模型
我有一个方法在我的控制器接受一个对象作为参数,并返回一个JsonResult 。 这个对象的属性之一是一个有三个可能值的枚举。 我认为,当客户端传入一个int属性它将填充枚举,但它不,它默认为0,枚举设置为它的第一个可能的select。
有什么build议么?
注意:这已经在MVC 4中解决了。如果升级到MVC 4是您的项目的一个可行的select,那么这就是所有你必须做的,以开始模型绑定到枚举。
这就是说,这里是MVC 3的解决方法,如果你仍然需要它。
问题在于MVC中的默认模型联编程序。 正确的整数值使其成为模型联编程序,但联编程序不编码映射到枚举的整数值。 如果传入的值是一个包含枚举值的string,它就会正确地绑定。 与此问题是,当您使用Json()
方法将C#对象parsing为JSON时,它会将整数值作为枚举值发送,而不是命名值。
最简单和最透明的解决方法是重写默认的模型绑定器,并编写一些自定义逻辑来修复绑定枚举的方式。
-
像这样创build一个新的类。
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); } } }
-
然后只需在Global.asax文件中注册它。
protected override void OnApplicationStarted() { base.OnApplicationStarted(); AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); // Register your new model binder ModelBinders.Binders.DefaultBinder = new EnumModelBinder(); }
而已。 现在,枚举将正确绑定在JSON对象上。
http://www.codetunnel.com/how-to-bind-to-enums-on-json-objects-in-aspnet-mvc-3
绑定到你的模型的钩子属性呢?
public class SomeModel { public MyEnum EnumValue { get; set; } public int BindToThisGuy { get { return (int) EnumValue; } set { EnumValue = (MyEnum)value; } } }
好了朋友们。 我已经找了几个方法来做到这一点,因为我厌倦了写愚蠢的工作,以避开.net框架中的这个缺陷。 基于几个线程,我编写了以下解决scheme。
免责声明,这不是一个完全自动的解决scheme,所以它不会工作。 鉴于我的实施,它的作品。 也许我的方式会帮助别人devise一些能为他们工作的东西。
首先,我创build了一个枚举存储库。 枚举不必驻留在这里,但需要从存储库中可见。
在存储库中,我创build了一个类和一个公共静态属性来公开一个枚举types的列表。
namespace MyApp.Enums { public enum ATS_Tabs { TabOne = 0, TabTwo = 1, TabThree = 2, TabFour = 3, TabFive = 4 }; public class ModelEnums { public static IEnumerable<Type> Types { get { List<Type> Types = new List<Type>(); Types.Add(typeof(ATS_Tabs)); return Types; } } } }
接下来,我创build了一个模型绑定器并实现了IModelBinder接口(参考kdawg的注释和链接)。
namespace MyApp.CustomModelBinders { public class EnumModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); ModelState modelState = new ModelState { Value = valueResult }; object actualValue = null; try { return Enum.ToObject(Type.GetType(bindingContext.ModelType.AssemblyQualifiedName), Convert.ToInt32(valueResult.AttemptedValue)); } catch (FormatException e) { modelState.Errors.Add(e); } bindingContext.ModelState.Add(bindingContext.ModelName, modelState); return actualValue; } } }
这可能有助于添加一些代码,以确保valueResult.AttemptedValue的转换不会失败。
接下来,我打开了上面创build的枚举types列表,并为它们添加了模型绑定器(…在Global.asax.cs中)。
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); foreach (Type type in ModelEnums.Types) { ModelBinders.Binders.Add(type, new EnumModelBinder()); } RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); }
我承认,这不是最直观的方式,但它对我来说很好。 随时让我知道,如果我可以优化这一点。