【问题标题】:Model binding error when implementing post-get-redirect pattern with temp data使用临时数据实现 post-get-redirect 模式时的模型绑定错误
【发布时间】:2025-11-30 13:00:02
【问题描述】:

我正在使用 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 参数的绑定模型数据,我看到一个布尔值@ 的数组987654328@ 字段支持视图表单中的复选框: 但是 Replace 字段有效,如果模型状态有效,则表单复选框状态的一切都会成功。

如果表单无效并且我将模型状态序列化为 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);

【问题讨论】:

  • 您能告诉我们您是如何将ModelState 的序列化编码为TempData 的吗?
  • 没问题,我已经更新了问题。

标签: c# asp.net-core


【解决方案1】:

问题是您实际上并没有遵循 post-redirect-get。重定向发生成功。如果存在验证错误,您只需再次返回视图。无需在TempData 中保留任何内容。连链接文章的作者都指出:

由于 PRG 的主要目的是防止重复提交表单,因此不一定要在表单无效时重定向用户。在这种情况下,请求不应该是修改状态,所以再次提交表单是有效的。

他误入歧途的地方是在整个使用TempData 进行无效提交并且仍然重定向东西。这显然是错误的,实际上我发现这个建议来自 Andrew Lock 有点令人惊讶。我经常参考他的文章,但显然从未注意到这一点。

在软件开发中,有一条不成文的黄金法则:不要成为独角兽。以与地球上几乎所有其他开发人员不同的方式做事并不会让你变得独一无二。它会让你成为一个白痴。

更新

哇。刚刚阅读了 cmets 并从 Andrew 那里发现了一个,他说:

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

就在那里完成交易。我的意思是这是一个有趣的思想实验,但如果它对编写它的人来说不够好,对其他人来说也不够好。

当用户刷新使用无效数据提交的页面时,所有这一切都消除了“确认表单重新提交”对话框。 PRG一般已经涵盖了post成功的情况。考虑到复杂性和所有额外的请求,对于可能永远不会发生的事情来说,这根本不值得。就个人而言,我发现用户害怕刷新页面,担心他们必须再次重新输入所有字段(具有讽刺意味的是,这个解决方案实际上会导致,否则它们会很好地刷新)。

【讨论】:

  • 我不确定我是否同意,如果您不重定向来自发布操作的每个响应,您将无法刷新页面而不重新发布。通过始终重定向,当您遇到表单错误然后被重定向到包含数据和模型错误的视图时,您可以刷新并从头开始。
  • 同样,大多数用户不仅不会刷新,即使他们这样做了,他们的期望是数据会保留下来,而不是被清除。这是一种非典型的,我什至会说反模式,方法,你引用的文章的作者甚至没有使用他自己。这是一个亲吻时刻。明智地选择。