Model Binding to Enums in ASP.NET MVC 3

后端 未结 3 1556
天命终不由人
天命终不由人 2020-11-30 21:42

I have a method in my controller that accepts an object as an argument and returns a JsonResult. One of the properties on this object is an enum with three possible values.

3条回答
  •  半阙折子戏
    2020-11-30 22:29

    Ok guys. I've looked up a few ways to do this because I was tired of writing stupid work around to get past this deficiency in the .Net framework. Based on a couple of threads, I have composed the following solution.

    Disclaimer, this is not a totally automated solution, so it will not work for all. Given my implementation, it works. Maybe my way will help someone else design something that will work for them.

    First, I created an enum respository. The enums don't have to reside here, but they would need to be visible from the repository.

    In the repository, I created a class and a public static property to expose a list of enum types.

    namespace MyApp.Enums
    {
        public enum ATS_Tabs { TabOne = 0, TabTwo = 1, TabThree = 2, TabFour = 3, TabFive = 4 };
    
        public class ModelEnums
        {
            public static IEnumerable Types
            {
                get
                {
                    List Types = new List();
                    Types.Add(typeof(ATS_Tabs));
                    return Types;
                }
            }
        }
    }
    

    Next, I created a model binder and implemented the IModelBinder interface (ref. kdawg's comment and link).

    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;
            }
        }
    }
    

    It might help to add some code to ensure the conversion of valueResult.AttemptedValue doesn't fail.

    Next, I looped through the list of enum types I created above and added model binders for them (...in 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);
        }
    

    I admit, this it not the most intuitive way, but it works great for me. Feel free to let me know if I can optimize this.

提交回复
热议问题