我需要接受来自用户的对象列表:
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; }
}
答案 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.");
}
}
}