我正在使用asp.net core 2.2,并尝试实现POST-REDIRECT-GET using TempData in ASP.NET Core中概述的模式。我有两个动作,如下所示:
[ImportModelState]
public async Task<IActionResult> Upload(int id, CancellationToken ct)
{
var model = new MyModel();
// ...
return this.View(model);
}
[HttpPost]
[ExportModelState]
public async Task<IActionResult> Upload(int id, MyModel model, CancellationToken ct)
{
// ...
}
访问get
视图,输入表单详细信息并提交后,我在post
操作中设置了一个断点,以查看MyModel
参数的绑定模型数据,我看到一个布尔型Replace
字段的数组,该数组支持视图表单中的复选框:但是,Replace
字段可以工作,并且如果模型状态有效,则两个复选框都成功状态。
如果表单无效,并且我将modelstate序列化为tempdata并在重定向到get
动作的情况下将其合并,则会收到异常System.InvalidOperationException: The parameter conversion from type 'Newtonsoft.Json.Linq.JArray' to type 'System.Boolean' failed because no type converter can convert between these types.
为什么模型绑定器为布尔字段创建一个数组(这是由于表单和复选框的语义所致?),该数组可以执行post
操作,但是相同的数据无法绑定到相同的数据重新填充视图时的模型类型?
对临时数据的序列化使用以下逻辑:
var errorList = modelState
.Select(kvp => new ModelStateTransferValue
{
Key = kvp.Key,
AttemptedValue = kvp.Value.AttemptedValue,
RawValue = kvp.Value.RawValue,
ErrorMessages = kvp.Value.Errors
.Select(p => p.ErrorMessage)
.ToList(),
});
反序列化和合并使用以下逻辑:
var errorList = JsonConvert.DeserializeObject<List<ModelStateTransferValue>>(serialized);
var modelState = new ModelStateDictionary();
foreach (var item in errorList)
{
modelState.SetModelValue(item.Key, item.RawValue, item.AttemptedValue);
foreach (var error in item.ErrorMessages)
{
modelState.AddModelError(item.Key, error);
}
}
filterContext.ModelState.Merge(modelState);
答案 0 :(得分:0)
问题是您实际上并没有遵循重定向后获取。重定向成功。如果存在验证错误,则只需再次返回视图。无需在TempData
中保留任何内容。甚至链接文章的作者也指出:
由于PRG的主要目的是防止重复提交表单,因此,如果表单无效,则不一定要重新引导用户。在这种情况下,请求不应处于修改状态,因此再次提交表单是有效的。
他误入歧途的地方是TempData
用于无效提交,并且仍然可以重定向。这显然是错误的,实际上,我的建议是来自安德鲁·洛克(Andrew Lock)的,这让我有些惊讶。我经常引用他的文章,但显然从来没有注意到它。
在软件开发中,有一个不言而喻的黄金法则:不要成为独角兽。与地球上几乎其他所有开发人员相比,做事都不同,这并不会使您与众不同。它使你成为白痴。
更新
哇。刚读完这些评论,发现安德鲁说了一个话:
话虽如此,我实际上并没有亲自使用这种方法-正如您所说的那样,它增加了很多复杂性
那已经完成了。我的意思是说这是一个有趣的思想实验,但是如果对编写它的人来说还不够好,那么对其他任何人也不够。
当用户刷新使用无效数据提交的页面时,所有这些操作都摆脱了“确认表单重新提交”对话框。 PRG通常已经涵盖了该职位成功的情况。考虑到复杂性以及所有额外的请求,对于甚至可能永远不会发生的事情,它甚至都不值得。就个人而言,我发现用户害怕刷新页面,担心他们将不得不重新输入所有字段(具有讽刺意味的是,此解决方案实际上会导致 ,而如果没有其他情况,它们会很好地刷新。)