【问题标题】:ASP.NET MVC Binding with Remote Validation带有远程验证的 ASP.NET MVC 绑定
【发布时间】:2015-07-29 11:27:04
【问题描述】:

我有一个模型 ModelA 和一个成员 toBeRemoteChecked 和一个模型 MapToA 和一个成员 valueToMap。每当我创建ModelA 的实例时,我还需要MapToA 的实例,所以我有一个模型CreateModelA,其中包括一个成员modelA 和一个成员valueToMap。提交表单后,我将modelA 添加到数据库表ModelA 并创建一个实例并将其添加到MapToA,该实例由modelAvalueToMap 组成。就代码而言

public class ModelA
{
    [Key]
    public int ID { get; set; }
    [Required, Remote("isValid", "MyController", ErrorMessage = "not valid")]
    public string toBeRemoteChecked { get; set; }
}

public class MapToA
{
    [Key]
    public int Map_ID { get; set; }
    [Required]
    public int modelAID { get; set; }
    [Required]
    public int valueToMap { get; set; }
}

public class CreateModelA
{
    public ModelA modelA { get; set; };
    public int valueToMap { get; set; };
}

当我编辑 ModelA 的实例时,MapToA 中的值无关紧要(在大多数情况下,mapToA 的多个实例具有相同的 modelA id),但远程验证toBeRemoteChecked 仍然很重要。

我的问题:验证方法的绑定:

public ActionResult isValid(string toBeRemoteChecked) { ... }

如果我保持原样,它在编辑ModelA 时可以工作,但在我通过CreateModelA 创建ModelA 时不会(我总是在toBeRemoteChecked 中得到空值)。当我使用 BindPrefix

public ActionResult isValid([Bind(Prefix = "modelA.toBeRemoteChecked")] string toBeRemoteChecked) { ... }

当我创建 ModelA 时它可以工作,但在我编辑它时却不行。

当我尝试通过在 @Html.TextBoxFor 的 htmlAttributes 中添加 ... @Name = "toBeRemoteChecked" ...(而不是由 HTML 帮助程序创建的 modelA.toBeRemoteChecked)来更改 Create.cshtml 中的“名称”时,验证工作正常,但是值与表的绑定丢失了,当值保存到数据库时出现错误(空值)。

那么,如何实现创建和编辑的不同绑定呢?

到目前为止,我的解决方法是制作ModelACreateModelA : IValidatableObject 并在我的public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 方法中检查成员toBeRemoteChecked。但是那个会在表单顶部显示错误消息,而不是在 TextFor 框的位置。

所以:最佳解决方案:如何进行绑定,使远程验证在这两种情况下都有效?

次优:如何在IValidatableObject所属的对象附近显示错误信息(并在手边获取错误信息,而不是提交后)

不同的想法或解决方案:欢迎。

谢谢。

【问题讨论】:

    标签: c# asp.net asp.net-mvc validation asp.net-mvc-4


    【解决方案1】:

    一个有趣的问题,类似于this question,因此我在 Codeplex 报告了一个问题,但尚未解决。该链接包含对 jquery.validate.js 文件的建议修改,这将解决此问题(它会去除前缀),但这意味着您在更新脚本时需要维护它,因此并不是很理想。

    一种选择是将CreateModelA 更改为从ModelA 继承并添加int valueToMap 属性,这样您就永远不会有前缀 - 您总是使用@Html.TextBoxFor(m => m.toBeRemoteChecked) 而不是@Html.TextBoxFor(m => m.modelA.toBeRemoteChecked)

    另外,[Remote] 是仅客户端验证,这意味着您在发布时仍需要在服务器中执行验证。因此,您可以接受您没有对该属性进行客户端验证,而是在该属性的 POST 方法中添加 ModelState 错误并返回视图,以便其显示在关联的 ValidationMessageFor()元素

    旁注:您的模型具有[Key] 属性的事实表明这是一个数据模型,而不是视图模型,而[Remote] 是一个特定于视图的属性。您应该使用视图模型,尤其是在编辑数据时。 (参考What is ViewModel in MVC?

    【讨论】:

    • 谢谢。至于客户端验证,我尝试了继承选项 - 也有一个演示项目工作,但是当我 db.ModelAset.Add(createModelA) 时,我要么最终将不需要的附加列自动添加到数据库中,要么在我手动后得到 invalid column name 错误从数据库中删除了这些列。当我通过将所有必要的成员从createModelA 复制到modelA 在控制器中手动创建modelA 时,我可以db.ModelAset.Add(modelA)。这有捷径吗? (我的真实模型有大约 20 个成员,所以这是可能的,但不是很好)。谢谢。
    • 你需要再读一遍我的最后一段 :) 视图模型与数据库没有关系。
    • 好的。所以在将数据从视图模型移动到数据模型时,我需要付出额外的努力,感谢您的帮助:-)
    • 我还不是很高兴 - 视图模型在某些地方使我的代码翻倍(将 20 个成员从 a 复制到 b 并返回,当我使用我的数据模型时没有必要) - 没有视图模型(和获取绑定以进行客户端验证的继承选项),实体框架在数据库中生成这个不需要的鉴别器列,并希望时不时使用它(createModel 从未打算写入数据库),所以删除它以非工作代码结束 - 对我来说,这是一个很大的解决方法,只是为了简单地绑定到我的验证例程 - 那么:是否有另一种方法可以解决绑定问题?
    • 这根本不是解决办法。使用视图模型是表示您在视图中显示的数据的推荐且正确的方法。并且视图特定属性永远不应该在数据模型中。不,没有其他方法 - 只是以正确的方式去做!
    【解决方案2】:

    我找到了一个没有继承(也没有视图模型)的解决方案,只需对我的代码进行少量更改即可解决我的绑定问题。

    远程验证有两种绑定方式,你可以只传递需要远程检查的成员

    public ActionResult isValid(string toBeRemoteChecked) { ... }
    

    或者您可以传递该成员的类的实例。

    public ActionResult isValid(ModelA modelA) { ... }
    

    当然,在第二个变体中,您必须将toBeRemoteChecked 替换为modelA.toBeRemoteChecked。在第二个版本中,绑定在两种情况下都有效——在编辑时以及在上面的上下文中创建我的ModelA 实例时。为了使绑定工作,远程验证方法的参数名称必须与CreateModelA 中的成员名称匹配,在我的例子中是modelA

    如果您有一个非常复杂的模型,您可以使用绑定/包含将参数modelA 初始化为您想要使用的成员,即在我的情况下我会使用

    public ActionResult isValid([Bind(Include = "toBeRemoteChecked")] ModelA modelA) { ... }
    

    默认情况下(不包括包含),所有其他成员将保持为空或具有默认值 - 因此,仅当您还需要其他成员进行验证时才需要使用 Include - 在我的情况下,我会在省略时使用相同的包括)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多