Привязка модели к представлениям в ASP.NET MVC 3
У меня есть метод в моем контроллере, который принимает объект как аргумент и возвращает JsonResult. Одним из свойств этого объекта является перечисление с тремя возможными значениями. Я предположил, что, когда клиент передал в int для этого свойства, он заполнил бы перечисление, но это не так, оно по умолчанию равно 0, и перечисление установлено на первый из возможных вариантов.
Любые предложения?
Ответы
Ответ 1
ПРИМЕЧАНИЕ. Это было разрешено в MVC 4. Если обновление для MVC 4 является жизнеспособной опцией для вашего проекта, то это все, что вам нужно сделать, чтобы начать привязку модели к перечислениям.
Итак, вот обходной путь для MVC 3, если он вам еще нужен.
Проблема связана с привязкой модели модели по умолчанию в MVC. Правильное целочисленное значение делает его привязкой к модели, но связующее не кодируется для отображения целочисленного значения перечисления. Он правильно связывается, если переданное значение является строкой, содержащей именованное значение перечисления. Проблема заключается в том, что когда вы разбираете объект С# в JSON с помощью метода 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 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
Ответ 2
Как насчет привязки к свойству hook на вашей модели?
public class SomeModel
{
public MyEnum EnumValue { get; set; }
public int BindToThisGuy
{
get { return (int) EnumValue; }
set { EnumValue = (MyEnum)value; }
}
}
Ответ 3
Хорошо, ребята. Я искал несколько способов сделать это, потому что я устал писать глупое дело, чтобы преодолеть этот недостаток .Net framework. Основываясь на нескольких потоках, я составил следующее решение.
Отказ от ответственности, это не полностью автоматизированное решение, поэтому оно не будет работать для всех. Учитывая мою реализацию, она работает. Возможно, мой способ поможет кому-то создать что-то, что будет работать для них.
Сначала я создал репозиторий enum. Перечисления здесь не обязательно, но они должны быть видимыми из репозитория.
В репозитории я создал класс и общедоступное статическое свойство, чтобы вывести список типов перечислений.
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;
}
}
}
}
Затем я создал привязку модели и реализовал интерфейс 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 не подводит.
Далее я зациклился на списке типов перечислений, которые я создал выше, и добавил для них привязки к ним (... в 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);
}
Я признаю, что это не самый интуитивный способ, но он отлично работает для меня. Не стесняйтесь сообщить мне, могу ли я это оптимизировать.