模型与Asp.Core中的继承绑定

时间:2017-12-04 00:11:09

标签: asp.net asp.net-core .net-core

我需要接受来自用户的对象列表:

public async Task<IActionResult> CreateArticle(List<InformationBlockModel> informationBlocks)
    {
        ...
    }

ModelBinder应该确定具体类型,但是当我尝试将InformationBlock转换为TextInformationBlock时,抛出异常。

层次:

public class InformationBlockModel
{
    public virtual InformationBlockType Type { get; set; }
}

public class TextInformationBlockModel : InformationBlockModel
{
    public string Text { get; set; }

    public override InformationBlockType Type { get; set; } = InformationBlockType.Text;
}

public class ImageInformationBlockModel : InformationBlockModel
{
    public override InformationBlockType Type { get; set; } = InformationBlockType.Image;
    public string Name { get; set; }
}

2 个答案:

答案 0 :(得分:6)

最后,我找到了一个解决方案:

<强> Startup.cs

services.AddMvc()
    .AddJsonOptions(options => options.SerializerSettings.Converters.Add(new InformationBlockConverter()));

<强> JsonCreationConverter.cs

public abstract class JsonCreationConverter<T> : JsonConverter
{
    public override bool CanWrite { get; } = false;

    public override bool CanRead { get; } = true;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    }

    protected abstract T Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T) == objectType;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);

        var target = Create(objectType, jObject);

        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}

<强> InformationBlockConverter

public class InformationBlockConverter : JsonCreationConverter<InformationBlockModel>
{
    private readonly Dictionary<InformationBlockType, Type> _types = new Dictionary<InformationBlockType, Type>
    {
        {InformationBlockType.Text, typeof(TextInformationBlockModel)},
        {InformationBlockType.Image, typeof(ImageInformationBlockModel)},
        {InformationBlockType.Video, typeof(VideoInformationBlockModel)}
    };

    protected override InformationBlockModel Create(Type objectType, JObject jObject)
    {
        return (InformationBlockModel) jObject.ToObject(_types[Enum.Parse<InformationBlockType>(
            jObject.GetValue("type", StringComparison.InvariantCultureIgnoreCase).Value<string>(), true)]);
    }
}

<强> InformationBlockType

public enum InformationBlockType
{
    Text,
    Image,
    Video
}

答案 1 :(得分:2)

默认情况下,

Asp.Net绑定就像这样工作。如果你想要这种行为,你将不得不自己编写custom model binding,这并不困难。

或者,使用视图模型:

public class InformationBlockViewModel
{
    public string Type { get; set; }
    public string Text { get; set; }
    public string Name { get; set; }
}

然后处理控制器中的块类型:

public async Task<IActionResult> CreateArticle(List<InformationBlockViewModel> informationBlocks)
{
    foreach (var block in informationBlocks) {        
        switch (block.Type)
        {
            case "Text":
                // Handle text
                break;
            case "Image":
                // Handle image
                break;
            case default:
                throw new Exception("Unknown information block type.");
        }
    }
}