Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET MVC 3中与枚举的模型绑定_C#_Asp.net Mvc_Asp.net Mvc 3_Enums_Model Binding - Fatal编程技术网

C# ASP.NET MVC 3中与枚举的模型绑定

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)

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


有什么建议吗?

绑定到模型上的钩子属性怎么样

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);
            }
        }
    }
    
  • 就这样。枚举现在将正确绑定到JSON对象上


    好的,伙计们。我已经找到了一些方法来解决这个问题,因为我已经厌倦了编写愚蠢的工作来克服.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);
        }