[英]Model binding with inheritance in Asp.Core
I need to accept list of objects from user: 我需要接受来自用户的对象列表:
public async Task<IActionResult> CreateArticle(List<InformationBlockModel> informationBlocks)
{
...
}
ModelBinder should determine concrete types, but when I trying to cast InformationBlock to TextInformationBlock, exception throws. ModelBinder应该确定具体的类型,但是当我尝试将InformationBlock转换为TextInformationBlock时,异常抛出。
Hierarchy: 层次:
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; }
}
Finally, I found a solution: 最后,我找到了一个解决方案:
Startup.cs Startup.cs
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.Converters.Add(new InformationBlockConverter()));
JsonCreationConverter.cs 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 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 InformationBlockType
public enum InformationBlockType
{
Text,
Image,
Video
}
Asp.Net binding does not work like this by default. 默认情况下,Asp.Net绑定不能像这样工作。 If you want to this sort of behaviour you will have to write your own custom model binding , which isn't too difficult.
如果你想要这种行为,你将不得不编写自己的自定义模型绑定 ,这不是太困难。
Or, use a view model: 或者,使用视图模型:
public class InformationBlockViewModel
{
public string Type { get; set; }
public string Text { get; set; }
public string Name { get; set; }
}
Then handle the block type in the controller: 然后处理控制器中的块类型:
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.");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.