[英]Polymorphic model binding in AspNet Core WebApi?
任何人都有一個自定義 model 綁定與多態 model 綁定的工作示例? I'm trying this example (which is for Mvc not Api projects) with a web api project but it's not working for API projects. 我認為在填充ValueProvider
方面缺少一些步驟,但我找不到與此相關的任何資源(AspNet Core 3.1)。
到目前為止我的嘗試:
Dtos:
public abstract class Device
{
public string Kind { get; set; }
}
public class Laptop : Device
{
public string CPUIndex { get; set; }
}
public class SmartPhone : Device
{
public string ScreenSize { get; set; }
}
自定義 model 綁定器實現:
public class DeviceModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType != typeof(Device))
{
return null;
}
var subclasses = new[] { typeof(Laptop), typeof(SmartPhone), };
var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
foreach (var type in subclasses)
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
}
return new DeviceModelBinder(binders);
}
}
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)
{
var modelKindName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, nameof(Device.Kind));
var modelTypeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
IModelBinder modelBinder;
ModelMetadata modelMetadata;
if (modelTypeValue.FirstValue == "Laptop")
{
(modelMetadata, modelBinder) = binders[typeof(Laptop)];
}
else if (modelTypeValue.FirstValue == "SmartPhone")
{
(modelMetadata, modelBinder) = binders[typeof(SmartPhone)];
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
modelMetadata,
bindingInfo: null,
bindingContext.ModelName);
await modelBinder.BindModelAsync(newBindingContext);
bindingContext.Result = newBindingContext.Result;
if (newBindingContext.Result.IsModelSet)
{
// Setting the ValidationState ensures properties on derived types are correctly
bindingContext.ValidationState[newBindingContext.Result] = new ValidationStateEntry
{
Metadata = modelMetadata,
};
}
}
}
我像這樣注冊 model 活頁夾提供者:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(o => o.ModelBinderProviders.Insert(0, new DeviceModelBinderProvider()));
}
然后我的 controller:
[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
[HttpPost]
public IActionResult Test(Device dto)
{
var x = dto;
return Ok();
}
}
我發布了一個 json 請求正文,例如:
{
"ScreenSize": "1",
"Kind": "SmartPhone"
}
真的厭倦了這方面的文檔,因為發生了太多的魔法。 我的后備是從請求中手動解析 HttpContent 並反序列化。 但我希望像示例中那樣使用 model 活頁夾方法。 我看到的唯一兩件奇怪的事情是bindingContext.ModelName
是空的, bindingContext.ValueProvider
只有一個包含action
和controller
鍵的路由值提供程序。 因此,看起來主體甚至沒有解析到值提供者中。
當 JSON 數據不與 model 綁定\值提供程序子系統的 rest 交互時使用的格式化程序。 對於這種情況,您必須為您正在使用的 JSON 庫編寫轉換器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.