c# - aspnet 核心中的复杂自定义模型绑定与属性类中的继承
问题描述
我正在尝试使用继承的子类在 Core(2.2/3.1) 中进行自定义模型绑定。
我使用IModelBinderProvider和IModelBinder来操作我的模型绑定,因为 MVC 不知道是将基类转换Device
为 aTeddybear
还是 a Legobrick
。
IModelBinder
的BindModelAsync
方法被我的Product
类调用,我想那是我应该查找Data
属性并检查它的Kind
. 然后从参数中bindingContext.Model
挤出设备数据并将Data
属性的值替换为Teddybear
or Legobrick
。
但是bindingContext.Model
为空;我没有数据。
在MSDN的底部有一个示例,但其中的根是基类。
我有一个常规的根,但一个属性是一个基/继承的类构造。
在某个地方我没有正确连接呼叫,或者我没有找到读取数据的正确方法。
我想我IModelBinderProvider
是正确的,它捕获Product
类型并将绑定器添加到子类Teddybear
和Legobrick
.
public class DeviceTypeDataContractProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
if (context.Metadata.ModelType == typeof(Product))
{
foreach (var type in new[] { typeof(Teddybear), typeof(Legobrick) })
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
}
}
else
{
return null;
}
return new DeviceModelBinder(binders);
}
}
IModelBinder
/处的代码BindModelAsync
仍然让我无法理解。
public class DeviceModelBinder : IModelBinder
{
private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;
public DeviceModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> binders)
{
this.binders = binders;
}
public async Task BindModelAsync(ModelBindingContext bindingContext){
... I totally lost it here and am beginning to feel dizzy.
}
}
通过互联网来一个电话,如:
"product": {
"id": "56-1",
"data": {
"kind": "teddy",
"name": "Tutu"
}
}
或者
"product": {
"id": "66-1",
"data": {
"kind": "lego",
"studCount": 8
}
}
Aspnet 用于填充:
public class Product{
string Id {get;set;}
Device Data{get;set;}
}
public class Device{
string Kind {get;set}
}
public class Teddybear: Device{
string Name {get;set}
}
public class Legobrick: Device{
int StudCount {get;set}
}
控制器是常规的,并且连接了自定义建模:
[HttpPost]
public async Task<IActionResult> Create([FromBody] Product product){...
services.AddMvc(options => {
...
options.Filters.Add(new AuthorizeFilter(policy));
})
.AddJsonOptions(options => {
options.ModelBinderProviders.Insert(0, new DeviceTypeDataContractProvider());
});
解决方案
我认为文档中提供的解决方案不适用于您的情况,因为您使用json
. 一个简单的工作示例是
public class DeviceTypeDataContractProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(Product))
{
return new DeviceModelBinder();
}
return null;
}
}
public class DeviceModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var reader = new JsonTextReader(new StreamReader(bindingContext.HttpContext.Request.Body));
//loading request json
var jObject = JObject.Load(reader);
JToken data = jObject["data"];
Product result = jObject.ToObject<Product>();
switch (result.Data.Kind)
{
case "teddy":
result.Data = data.ToObject<Teddybear>();
break;
case "lego":
result.Data = data.ToObject<Legobrick>();
break;
default:
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(result);
return Task.CompletedTask;
}
}
推荐阅读
- android - 为什么 OnLocationChanged 中的位置有旧时间?
- ansible - 如何在执行期间注册的 ansible 变量中转义单引号。我不能使用“\”,因为变量在注册之前是未知的
- latex - 如何删除添加到书目条目的页码位置
- javascript - 我无法从 JQuery ajax 调用中加载部分 Django 模板
- r - 如何从 R 中的表中选择特定行?
- sql - SQL,将字符串转换为日期,以便我可以使用 GETDATE()
- reactjs - 图标不会出现在 WordPress 上
- git - 中华人民共和国失败;HTTP 413,如何单独推送提交
- python - 如何防止flasgger请求中的重定向?
- django - 根据其组类别为模型创建排序的最佳方法是什么?