为什么这个 属性 没有在我的 mvc 项目中序列化?

Why isn't this property being serialized in my mvc project?

最终目标是从我的 View 中序列化一个 abstract 类型,供我的 Controller 使用。

我的抽象类型有一个 enum 属性 ,其名称对应于具体派生类型的名称;这就是我将如何确定 select 的具体类型。这个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 class 被 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 在它的 ValueProvider.FormValueProvider 中没有 BlockType 对于我的 BlockType 属性 - 但 NameHeightWidthDepth 属性按预期列出。

它们在 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 助手只生成通常的标签、基于类型(枚举、字符串等)的编辑器和验证消息。枚举的编辑器模板如下:

@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>

您的 select 元素似乎没有呈现该元素的 name。如果没有 name 属性,数据将不会与您模型中的适当 属性 相匹配。 您可以通过在浏览器中编辑 HTML 并在 select 输入中添加属性 name="BlockType" 来仔细检查它,然后尝试发布表单以查看它是否有效。