使用临时数据实现获取后重定向模式时的模型绑定错误

时间:2019-09-13 13:35:44

标签: c# asp.net-core

我正在使用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字段的数组,该数组支持视图表单中的复选框:model state但是,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);

1 个答案:

答案 0 :(得分:0)

问题是您实际上并没有遵循重定向后获取。重定向成功。如果存在验证错误,则只需再次返回视图。无需在TempData中保留任何内容。甚至链接文章的作者也指出:

  

由于PRG的主要目的是防止重复提交表单,因此,如果表单无效,则不一定要重新引导用户。在这种情况下,请求不应处于修改状态,因此再次提交表单是有效的。

他误入歧途的地方是TempData用于无效提交,并且仍然可以重定向。这显然是错误的,实际上,我的建议是来自安德鲁·洛克(Andrew Lock)的,这让我有些惊讶。我经常引用他的文章,但显然从来没有注意到它。

在软件开发中,有一个不言而喻的黄金法则:不要成为独角兽。与地球上几乎其他所有开发人员相比,做事都不同,这并不会使您与众不同。它使你成为白痴。

更新

哇。刚读完这些评论,发现安德鲁说了一个话:

  

话虽如此,我实际上并没有亲自使用这种方法-正如您所说的那样,它增加了很多复杂性

那已经完成了。我的意思是说这是一个有趣的思想实验,但是如果对编写它的人来说还不够好,那么对其他任何人也不够。

当用户刷新使用无效数据提交的页面时,所有这些操作都摆脱了“确认表单重新提交”对话框。 PRG通常已经涵盖了该职位成功的情况。考虑到复杂性以及所有额外的请求,对于甚至可能永远不会发生的事情,它甚至都不值得。就个人而言,我发现用户害怕刷新页面,担心他们将不得不重新输入所有字段(具有讽刺意味的是,此解决方案实际上会导致 ,而如果没有其他情况,它们会很好地刷新。)