我有一个复杂的模型,我想在表单中发布,但它没有被绑定。只有第一层有数据。 Model.Items 和后续的 item.Items 不会被绑定。组件交互正常,按预期删除和添加项目。
所有代码都被缩短了一点,以便于阅读:)这些是模型:
public class NewOrEditFactoryOrderVM
{
public int FactoryOrderId { get; set; }
public int? OrderId { get; set; } = null;
public int No { get; set; }
public DateTime DocDate { get; set; }
public List<NewOrEditFactoryOrderItemVM>? Items = new List<NewOrEditFactoryOrderItemVM>();
}
public class NewOrEditFactoryOrderItemVM
{
public int FactoryOrderItemId { get; set; }
public int FactoryOrderId { get; set; }
...
public List<NewOrEditFactoryItemComponentVM>? Items { get; set; } = new List<NewOrEditFactoryItemComponentVM>();
}
public class NewOrEditFactoryItemComponentVM
{
public int FactoryItemComponentId { get; set; }
public int FactoryOrderItemId { get; set; }
public int ProductId { get; set; }
...
}
我有带有表格的父组件:
<EditForm Model="Model" OnValidSubmit="Submit" FormName="NewOrEditFactoryOrder" Enhance>
<div class="row">
<div class="col-20">
<DataAnnotationsValidator />
<ValidationSummary />
</div>
<div class="clearfix"></div>
<div class="col-md-2">
<input type="hidden" @bind="@Model.FactoryOrderId" />
<input type="hidden" @bind="@Model.OrderId" />
<label for="WorkOrderNo" class="form-label">@Frontend.No<span class="text-danger"> *</span></label>
<InputNumber class="form-control" @bind-Value="Model.No" />
<ValidationMessage For="(() => Model.No)" />
</div>
<div class="col-md-3">
<label for="DocDate" class="form-label">@Frontend.Date<span class="text-danger"> *</span></label>
<InputDate class="form-control" @bind-Value="Model.DocDate" />
<ValidationMessage For="(() => Model.DocDate)" />
</div>
<div class="clearfix"></div>
<div class="col-md-3">
<label class="form-label">@Frontend.SearchProduct <span class="text-danger">*</span></label>
<input type="text" placeholder="@Frontend.SearchPlaceholder" class="form-control" @oninput=@SearchProduct />
@if (productsDD != null)
{
<ul class="list-group">
@foreach (var item in productsDD)
{
if (item.Selected == true)
{
<li @onclick="() => SelectConnectedWarehouse(item.Id)" class="list-group-item" data-bs-toggle="modal" data-bs-target="#[email protected]">@item.Name</li>
}
else
{
<li @onclick="() => AddProduct(item.Id, null)" class="list-group-item">@item.Name</li>
}
}
</ul>
}
</div>
<div class="col-md-17">
<CascadingValue Value="Model" Name="Model">
<NOEFactoryOrderItemCom ></NOEFactoryOrderItemCom>
</CascadingValue>
</div>
<div class="clearfix"></div>
<div class="col text-end">
<input type="submit" value="@Frontend.Save" class="btn btn-primary" />
</div>
</div>
</EditForm>
在表单内,我调用另一个组件来管理 Model.Items:
<CascadingValue Value="Model" Name="Model">
<NOEFactoryOrderItemCom ></NOEFactoryOrderItemCom>
</CascadingValue>
内容:
@if (Model != null && Model.Items != null && Model.Items.Any())
{
<hr />
foreach (var item in Model.Items)
{
<div class="row">
<input type="hidden" @bind="@item.FactoryOrderItemId" />
<input type="hidden" @bind="@item.FactoryOrderId" />
<input type="hidden" @bind="@item.OrderItemId" />
<div class="col-md-4">
<label for="Items.Description" class="form-label">
@item.ProductName
@if (item.ConnectedId != null && item.ConnectedId > 0)
{
<span> + </span>
@item.ConnectedName
}
</label>
@if (string.IsNullOrWhiteSpace(item.Comment))
{
<InputTextArea class="form-control" @bind-Value="@item.Comment" rows="1" />
}
else
{
<InputTextArea class="form-control" @bind-Value="@item.Comment" rows="4" />
}
</div>
<div class="col-md-2">
<label for="Items.Quantity" class="form-label gremlin-label">@Frontend.Quantity</label>
<InputNumber class="form-control" @[email protected] TValue="decimal" />
</div>
<div class="col-sm-12"> </div>
<div class="col-md-1">
<button type="button" class="btn btn-danger" @onclick="@(() => RemoveItem(item))">
<i class="bi bi-x-circle-fill"></i>
</button>
</div>
</div>
<div class="row">
<CascadingValue Name="Items" Value="item.Items">
<NOEFactoryItemComponentCom ></NOEFactoryItemComponentCom>
</CascadingValue>
</div>
<hr />
}
}
@code {
[Inject]
private IFactoryServices _factory { get; set; } = null!;
[CascadingParameter(Name = "Model")]
public NewOrEditFactoryOrderVM? Model { get; set; }
最后2.子组件:
@if (SubItems != null && SubItems.Any())
{
foreach (var subItem in SubItems)
{
<div class="col-md-1 col-sm-1"> </div>
<div class="col-md-4">
<label class="form-label gremlin-label">@Frontend.Item</label>
<br />
@subItem.ProductName
</div>
<div class="col-md-2">
<label for="Items.Quantity" class="form-label gremlin-label">@Frontend.Quantity</label>
<InputNumber class="form-control" @[email protected] TValue="decimal" />
</div>
@if (subItem.IsService)
{
<div class="col-md-2">
<label for="Items.Workers" class="form-label gremlin-label">@Frontend.Workers</label>
<InputNumber class="form-control" @bind-Value="@subItem.Workers" TValue="int" />
</div>
}
else
{
<input type="hidden" name="Items.Workers" value="1" />
<div class="col-md-2"> </div>
}
@if (subItem.HasDimensions)
{
<div class="col-md-3">
<label for="subItem.x" class="form-label gremlin-label">@Frontend.X</label>
<InputNumber class="form-control" @bind-Value="@subItem.x" TValue="decimal?" />
</div>
<div class="col-md-3">
<label for="subItem.y" class="form-label gremlin-label">@Frontend.Y</label>
<InputNumber class="form-control" @bind-Value="@subItem.y" TValue="decimal?" />
</div>
<div class="col-md-3">
<label for="subItem.z" class="form-label gremlin-label">@Frontend.Z</label>
<InputNumber class="form-control" @bind-Value="@subItem.z" TValue="decimal?" />
</div>
}
else
{
<div class="col-md-9"> </div>
}
<div class="col-md-1">
<button type="button" class="btn btn-danger" @onclick="@(() => RemoveSubItem(subItem))">
<i class="bi bi-x-circle-fill"></i>
</button>
</div>
<div class="clearix"> </div>
}
}
@code {
[Inject]
private IFactoryServices _factory { get; set; } = null!;
[CascadingParameter(Name ="Items")]
public List<NewOrEditFactoryItemComponentVM>? SubItems { get; set; }
}
所以。事实上问题不在于表单绑定。调试 Blazor WebAssembly 很困难。
问题是数据序列化未按预期执行。唯一有效的解决方案是使用 Newtonsoft.Json:
发送部分:
public async Task<NewOrEditFactoryOrderVM?> SaveFactoryOrder(NewOrEditFactoryOrderVM? vm)
{
if(vm != null)
{
string json = JsonConvert.SerializeObject(vm);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("api/Factory/SaveFactoryOrder", content);
if (response.IsSuccessStatusCode)
{ ... rest of logic
API 方面:
[HttpPost("SaveFactoryOrder")]
public async Task<ActionResult<NewOrEditFactoryOrderVM>> SaveFactoryOrder()
{
try
{
string requestBody = await new StreamReader(Request.Body).ReadToEndAsync();
NewOrEditFactoryOrderVM? vm = JsonConvert.DeserializeObject<NewOrEditFactoryOrderVM>(requestBody);
... rest of logic
我希望这对某人有帮助。我小时和很多挫折。无法找到根本原因:(
您是否验证服务器中的用户输入?您之前尝试过哪些替代方案?我面临着同样的问题,有些人建议使用 Fluent Validation:https://github.com/Blazored/FluentValidation 但就目前而言,它不起作用。