C# ASP.NET MVC 3中与枚举的模型绑定
我的控制器中有一个方法,它接受一个对象作为参数并返回一个参数。此对象的属性之一是具有三个可能值的枚举。我假设当客户机为该属性传入int时,它将填充枚举,但它没有,它默认为0,并且枚举被设置为它可能选择的第一个C# ASP.NET MVC 3中与枚举的模型绑定,c#,asp.net-mvc,asp.net-mvc-3,enums,model-binding,C#,Asp.net Mvc,Asp.net Mvc 3,Enums,Model Binding,我的控制器中有一个方法,它接受一个对象作为参数并返回一个参数。此对象的属性之一是具有三个可能值的枚举。我假设当客户机为该属性传入int时,它将填充枚举,但它没有,它默认为0,并且枚举被设置为它可能选择的第一个 有什么建议吗?绑定到模型上的钩子属性怎么样 public class SomeModel { public MyEnum EnumValue { get; set; } public int BindToThisGuy { get { return (int)
有什么建议吗?绑定到模型上的钩子属性怎么样
public class SomeModel
{
public MyEnum EnumValue { get; set; }
public int BindToThisGuy
{
get { return (int) EnumValue; }
set { EnumValue = (MyEnum)value; }
}
}
注意:这已在MVC 4中得到解决。如果升级到MVC 4对您的项目来说是一个可行的选择,那么这就是开始将模型绑定到枚举所必须做的一切 也就是说,如果您仍然需要MVC 3,这里有一个变通方法
问题在于MVC中的默认模型绑定器。正确的整数值将映射到模型绑定器,但绑定器未编码为映射到枚举的整数值。如果传入的值是包含枚举的命名值的字符串,则它将正确绑定。问题在于,当您使用
JSON()
方法将C#对象解析为JSON时,它会将整数值作为枚举值而不是命名值发送
最简单、最透明的修复方法是覆盖默认的模型绑定器,并编写一些自定义逻辑来修复绑定枚举的方式
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);
}
}
}
好的,伙计们。我已经找到了一些方法来解决这个问题,因为我已经厌倦了编写愚蠢的工作来克服.Net框架中的这个缺陷。基于几个线程,我编写了以下解决方案 免责声明,这不是一个完全自动化的解决方案,因此它不会适用于所有人。根据我的实现,它是有效的。也许我的方法可以帮助其他人设计出适合他们的东西 首先,我创建了一个enum respository。枚举不必驻留在这里,但它们需要在存储库中可见 在存储库中,我创建了一个类和一个公共静态属性来公开枚举类型列表
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;
}
}
}
}
添加一些代码可能有助于确保valueResult.AttemptedValue的转换不会失败
接下来,我遍历了我在上面创建的枚举类型列表,并为它们添加了模型绑定(…在Global.asax.cs中)
我承认,这不是最直观的方式,但对我来说效果很好。请随时告诉我是否可以对此进行优化。是否尝试将下拉选择绑定到它?否。它是一个以JSON形式传回的对象,然后在下一个AJAX请求中,它将JSON对象传回服务器。我正在将模型绑定到此JSON对象。此对象的属性之一是C#代码中的枚举。在客户端,我可以看到,当我将C#对象序列化为json时,它会正确地使用枚举的整数值填充json对象,但当我将其传回并绑定到它时,枚举默认为零。您的枚举基于int吗?enum MyEnum:int{MyEnumValue=3}另外,如果使用字符串值(而不是int),它也将绑定。您还可以为枚举创建自定义模型绑定器。这听起来像是未设置枚举属性时的行为。。这不是你的情况,因为我怀疑在firebug中,我可以看到json对象具有正确的int,并且正在使用正确的int发出ajax请求。当我在服务器上调试时,枚举默认为零(好像没有设置)。感谢提供信息。服务器到客户端的默认行为是Enum->int,但客户端到服务器的默认行为是string->Enum,这让人非常失望。好东西。@kdawg,确实令人失望。然而,在MVC团队的一个视频演示中,我确实记得有人提到他们打算在未来的版本中修复enum支持,尽管你可能不应该引用我的话。我想知道——是从DefaultModelBinder继承还是用EnumModelBinder实现IModelBinder接口更好?Phil Haack举了一个例子:我还没有完全实现IModelBinder枚举解决方案。我之所以提出这个问题,是因为我需要一个十进制活页夹(如Haack的帖子),而且在ModelBinders.binders集合中添加特定于类型的活页夹似乎更干净(即:add(typeof(enum),EnumModelBinder);.add(typeof(Decimal),DecimalModelBinder))而不是在MyModelBinderHa中检查每个类型!当然,不存在类型为的IsDecimal属性。这降低了在MyModelBinder方法中处理模型绑定到小数的难度……而且,typeof(enum)也在爆炸。Soooo,别理我。=)您是否正在查看此代码?尝试你是不是想分享你解决问题的方法,而不是这个?关于它的博客。
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;
}
}
}
}
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;
}
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
foreach (Type type in ModelEnums.Types)
{
ModelBinders.Binders.Add(type, new EnumModelBinder());
}
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}