ASPNET Core 中的复杂自定义模型绑定,在属性的类中具有继承



我正在尝试使用继承的子类在 Core(2.2/3.1( 中进行自定义模型绑定。

我使用 IModelBinderProvider和 IModelBinder 来操作我的模型绑定,因为 MVC 不知道是将基类Device转换为Teddybear还是Legobrick

IModelBinderBindModelAsync方法被调用用于我的Product类,我想这就是我应该查找Data属性并检查其Kind的地方。然后从参数bindingContext.Model拉伸设备数据,并将Data属性的值替换为TeddybearLegobrick
bindingContext.Model是无效的;我没有数据。

在 MSDN 的底部有一个示例,但在其中,根是基类。我有一个常规根,但属性是基/继承类构造。

在某处我没有正确连接呼叫,或者我没有找到读取数据的正确方法。


我想我的IModelBinderProvider是正确的,它捕获了Product类型并将粘合剂添加到子类TeddybearLegobrick.

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

相关内容

  • 没有找到相关文章

最新更新