简体   繁体   English

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

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

The ultimate goal is to serialize an abstract type from my View to be consumed by my Controller . 最终目标是序列化Viewabstract类型,以供Controller

My abstract type has an enum property whose names correspond to the names of the concrete derived types; 我的抽象类型具有一个enum属性,其名称与具体派生类型的名称相对应; this is how I will determine which concrete type to select. 这就是我确定选择哪种具体类型的方式。 The value of this enum is set in the constructor of the abstract type via reflection: 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 { /*...*/ }

The Block class is used by Entity Framework but the BlockType property is not stored in the database, so the BlockType property is marked with the [NotMapped] attribute; 实体框架使用Block类,但是BlockType属性未存储在数据库中,因此BlockType属性用[NotMapped]属性标记; however, since I want the property to be round-tripped from the View to the Controller, I have marked it with the [JsonProperty] attribute. 但是,由于我希望该属性从View到Controller往返,因此我已使用[JsonProperty]属性对其进行了标记。

I have created a TestModelBinder to handle the deserialization from the View to the Controller: 我创建了一个TestModelBinder来处理从View到Controller的反序列化:

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

When I hit that breakpoint above, the bindingContext does not have a BlockType in its ValueProvider.FormValueProvider for my BlockType property - but the Name , Height , Width and Depth properties are listed as expected. 当我打上面的断点,在bindingContext没有一个BlockType在其ValueProvider.FormValueProviderBlockType财产-但NameHeightWidthDepth的属性被列为预期。

They're all listed the same way in the EditorTemplate: 它们在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>

... and the BootstrapEditorGroupFor helper just generates the usual label, editor based on type (enum, string, etc), and validation message. ...,而BootstrapEditorGroupFor帮助器仅生成常规标签,基于类型(枚举,字符串等)的编辑器以及验证消息。 The EditorTemplate for Enums is below: 枚举的EditorTemplate如下:

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

Your select element doesn't seems to be rendering the name of the element. 您的select元素似乎未呈现该元素的name Without the name attribute the data will not get matched to the appropriate property in you model. 没有name属性,数据将无法与模型中的适当属性匹配。 You can double check it by just editing the HTML in your browser and adding an attribute name="BlockType" to your select input and try posting the form to see if it works. 您可以通过仅在浏览器中编辑HTML并在选择的输入中添加属性name="BlockType" ,然后尝试发布表单以查看其是否有效来再次检查它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM