使用自定义模型绑定器的递归模型绑定

Posted

技术标签:

【中文标题】使用自定义模型绑定器的递归模型绑定【英文标题】:Recursive model binding with custom model binder 【发布时间】:2012-07-31 07:31:11 【问题描述】:

我正在尝试使用 .NET MVC 在我的表单中实现向导功能。我遇到了 Darin Dimitrov 的 method of achieving 这个。基本上他有一个向导视图模型,其中包含一个 IStep 列表。每个步骤都有自己的属性和验证。

他在视图上序列化向导(作为一种视图状态),然后将其和当前步骤发布到控制器。因此,向导的每个步骤,您只验证该步骤。如果成功,则增加当前步骤并重复。

在大多数情况下 - 这非常有效。但是,我在验证各个步骤时遇到了一个问题,因为我的一些步骤依赖于之前提交的验证值。

因此,我需要添加一种方法来允许各个向导步骤访问之前的步骤。

我决定这样做的方法是将向导包含在步骤中。

public interface IWizardStep

    WizardViewModel Wizard  get; set; 

然后在提供的模型绑定器 Darin 中,为 BindModel 添加一个覆盖

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

    var step = (IStepViewModel)base.BindModel(controllerContext, bindingContext);
    step.Wizard = (WizardViewModel)serializer.Deserialize(controllerContext.HttpContext.Request.Form["wizard"], SerializationMode.Signed);
    return step;

这似乎可行,但是在我的控制器中我有一个 ModelStateError:

从类型'System.String'到类型的参数转换 “向导”失败,因为没有类型转换器可以 在这些类型之间进行转换。

我认为这是因为模型绑定器试图递归绑定?

有谁知道我该如何解决这个问题?或者 - 我是否正确地接近这个?有没有更好的方法来做到这一点?

我把上面所有的都是basic sample project来说明我遇到的问题。

【问题讨论】:

不可能将其存储在数据库中吗?你在一个无状态的世界里拼凑持久性.. @SimonWhitehead 不,这不是答案。事实上 - 我决定将它存储在会话中。 【参考方案1】:

将此添加到您的 HomeController 作为第 18 行...

ModelState.Remove("Wizard");

您应该可以使用,但更好的方法可能是将所有步骤的属性添加到单个模型类,然后为每个步骤使用验证组...

https://nuget.org/packages/Mvc3ValidationGroups

【讨论】:

谢谢。从模型状态中删除属性确实有效 - 如果没有修复错误的下划线原因。我会看看验证组。干杯。【参考方案2】:

所以我从来没有深入了解为什么这不起作用,而是决定省去自己的头痛并将向导保存在会话中,而不是序列化并在每一步都将其发布回来。这样,我可以轻松地在视图模型的 Validate(ValidationContext) 方法中获取向导。看起来效果不错。

【讨论】:

以上是关于使用自定义模型绑定器的递归模型绑定的主要内容,如果未能解决你的问题,请参考以下文章

.NET Core 自定义模型绑定器调用默认模型绑定器

将自定义模型绑定器应用于 asp.net 核心中的对象属性

自定义模型绑定器未针对 ASP.NET Core 2 中的单个属性触发

泛型类型的自定义模型绑定

属性的自定义配置绑定器

P23 自定义Model绑定器