Конечная цель заключается в сериализации типа abstract
из моего View
для использования моим Controller
.
Мой абстрактный тип имеет свойство enum
, имена которого соответствуют именамконкретные производные типы;так я определю, какой конкретный тип выбрать.Значение этого enum
устанавливается в конструкторе абстрактного типа с помощью отражения:
[JsonConverter(typeof(BlockJsonConverter)]
public abstract class Block{
[NotMapped, JsonProperty]
public BlockType BlockType {get; set;}
public string Name {get;set:}
public int Height{get;set;}
public int Width {get;set;}
public int Depth {get;set;}
protected Block(){
BlockType = Enum.TryParse(GetType().Name, out BlockType blocktype)
?? blocktype : BlockType.Unknown
}
}
public enum BlockType {
Long, Short, Tall, Unknown
}
public class Long : Block { /*...*/ }
public class Short : Block { /*...*/ }
public class Tall : Block { /*...*/ }
public class Unknown : Block { /*...*/ }
Класс Block
используется Entity Framework, но свойство BlockType
не сохраняется в базе данных.поэтому свойство BlockType
помечено атрибутом [NotMapped]
;однако, поскольку я хочу, чтобы свойство было подвергнуто циклическому переключению из представления в контроллер, я пометил его атрибутом [JsonProperty]
.
Я создал TestModelBinder
для обработки десериализации из представленияКонтроллеру:
public class TestModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext,
ModelBindingContext bindingContext, Type modelType)
{
return base.CreateModel(controllerContext, bindingContext,
GetModelType(controllerContext, bindingContext, modelType));
}
protected override ICustomTypeDescriptor GetTypeDescriptor(
ControllerContext controllerContext,ModelBindingContext bindingContext)
{
var modelType = GetModelType(controllerContext, bindingContext, bindingContext.ModelType);
return new AssociatedMetadataTypeTypeDescriptionProvider(modelType)
.GetTypeDescriptor(modelType);
}
private static Type GetModelType(ControllerContext controllerContext, ModelBindingContext bindingContext,
Type modelType)
{
if (modelType.Name == "Block")
{
• breakpoint
// get the value from bindingContext for BlockType
// and return the concrete type based on that
}
return modelType;
}
}
Когда я достигаю этой точки останова выше, bindingContext
не имеет BlockType
в ValueProvider.FormValueProvider
для моего свойства BlockType
- но * 1027Свойства *, Height
, Width
и Depth
перечислены в соответствии с ожиданиями.
Все они перечислены одинаково в EditorTemplate:
@model Block
<div class="form-row">
<div class="col">
@Html.BootstrapEditorGroupFor(m => m.Name)
</div>
<div class="col">
@Html.BootstrapEditorGroupFor(m => m.BlockType)
</div>
</div>
<div class="form-row">
<div class="col">
@Html.BootstrapEditorGroupFor(m => m.Height)
</div>
<div class="col">
@Html.BootstrapEditorGroupFor(m => m.Width)
</div>
<div class="col">
@Html.BootstrapEditorGroupFor(m => m.Depth)
</div>
</div>
... а помощник BootstrapEditorGroupFor
просто генерирует обычную метку, редактор на основе типа (enum, string и т. д.) и сообщение проверки.Шаблон Editor для перечислений приведен ниже:
@model Enum
@{
var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType)
?? ViewData.ModelMetadata.ModelType;
}
<div class="form-group">
<select class="form-control">
@if (ViewData.ModelMetadata.IsNullableValueType)
{
<option selected="@ReferenceEquals(Model, null)">Not Specified</option>
}
@foreach (var value in Enum.GetValues(type))
{
<option selected="@value.Equals(Model)">@value</option>
}
</select>
</div>