如何解决多态模型绑定/复杂模型
我在模型绑定中遇到问题。当我提交表格时,它返回我id = 0且设备为null?以及如何解决。我的目标是添加新设备,并通过选择器从视图中选择设备类型。如果用户选择智能手机,则必须为智能手机添加字段。我不想将基类中的设备类型另存为Kind变量。预先感谢(对不起英语)
controller->
public IActionResult Index()
{
MainCont mainCont = new MainCont();
return View(mainCont);
}
index.cshtml->
@model MainCont
@{
ViewData["Title"] = "Home Page";
}
<form action="home/create" method="post">
@Html.Partial("example",Model.Device)
<button type="submit">გაგზავნა</button>
</form>
example.cshtml->
@model SmartPhone
@Html.TextBoxFor(model => model.imei)
@Html.TextBoxFor(model => model.screensize)
设备型号->
public abstract class Device : Object
{
}
LaptopModel->
public class Laptop : Device
{
public string CPU { get; set; }
public string GPu { get; set; }
}
MainCont->
public class MainCont
{
public int Id{ get; set; }
public Device Device { get; set; }
}
SmartphoneModel->
public class SmartPhone : Device
{
public string screensize { get; set; }
public string imei { get; set; }
}
模型活页夹->
using Bind.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bind
{
public class DeviceModelBinder : IModelBinder
{
private Dictionary<Type,(ModelMetadata,IModelBinder)> binders;
public DeviceModelBinder(Dictionary<Type,IModelBinder)> binders)
{
this.binders = binders;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
IModelBinder modelBinder;
ModelMetadata modelMetadata;
if (bindingContext.ModelType == typeof(Laptop))
{
(modelMetadata,modelBinder) = binders[typeof(Laptop)];
}
else if (bindingContext.ModelType == typeof(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,};
}
}
}
}
binderprovider->
using Bind.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bind
{
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,IModelBinder)>();
foreach (var type in subclasses)
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata,context.CreateBinder(modelMetadata));
}
return new DeviceModelBinder(binders);
}
}
}
解决方法
这是一个演示:
Index.cshtml(选择智能手机时,请使用example.cshtml,选择笔记本电脑时,请使用example1.cshtml):
@model MainCont
@{
ViewData["Title"] = "Home Page";
}
<form asp-action="create" asp-controller="home" method="post">
<select id="select" name="select">
<option value="SmartPhone">SmartPhone </option>
<option value="Laptop">Laptop </option>
</select>
<div id="sample"></div>
<button type="submit">გაგზავნა</button>
</form>
@section scripts{
<script>
$(function () {
GetPartialView();
})
$("#select").change(function () {
GetPartialView();
})
function GetPartialView() {
$.ajax({
url: "/Test1/ReturnExample",type: "POST",data: {
select: $("#select").val()
},success: function (data) {
$('#sample').html(data);
},error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
}
example.cshtml:
@model SmartPhone
@Html.TextBoxFor(model => model.imei)
@Html.TextBoxFor(model => model.screensize)
example1.cshtml:
@model Laptop
@Html.TextBoxFor(model => model.CPU)
@Html.TextBoxFor(model => model.GPu)
控制器:
public IActionResult Index()
{
return View(new MainCont());
}
public IActionResult ReturnExample(string select)
{
if (select == "SmartPhone")
{
return PartialView("~/Views/Test1/example.cshtml",new SmartPhone());
}
else {
return PartialView("~/Views/Test1/example1.cshtml",new Laptop());
}
}
在家庭控制器中创建操作:
[HttpPost]
public IActionResult Create([ModelBinder(typeof(DataBinder))]MainCont mainCont) {
return Ok();
}
DataBinder:
public class DataBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var model1 = new MainCont();
var select = bindingContext.ValueProvider.GetValue("select").FirstValue;
if (select == "SmartPhone")
{
var model2 = new SmartPhone();
model2.screensize = bindingContext.ValueProvider.GetValue("screensize").FirstValue;
model2.imei = bindingContext.ValueProvider.GetValue("imei").FirstValue;
model1.Device = model2;
}
else if (select == "Laptop")
{
var model2 = new Laptop();
model2.CPU = bindingContext.ValueProvider.GetValue("CPU").FirstValue;
model2.GPu = bindingContext.ValueProvider.GetValue("GPu").FirstValue;
model1.Device = model2;
}
bindingContext.Result = ModelBindingResult.Success(model1);
return Task.CompletedTask;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。