C# 带有远程验证的ASP.NET MVC绑定

C# 带有远程验证的ASP.NET MVC绑定,c#,asp.net,asp.net-mvc,validation,asp.net-mvc-4,C#,Asp.net,Asp.net Mvc,Validation,Asp.net Mvc 4,我有一个模型ModelA,其中一个成员toBeRemoteChecked,还有一个模型MapToA,其中一个成员valueToMap。每当我创建ModelA的实例时,我还需要MapToA的实例,因此我有一个模型CreateModelA,其中包括一个成员ModelA和一个成员valueToMap。提交表单时,我将modelA添加到数据库表modelA,并创建一个实例并将其添加到MapToA,该实例由modelA的id和valueToMap组成。在代码方面 public class ModelA {

我有一个模型
ModelA
,其中一个成员
toBeRemoteChecked
,还有一个模型
MapToA
,其中一个成员
valueToMap
。每当我创建
ModelA
的实例时,我还需要
MapToA
的实例,因此我有一个模型
CreateModelA
,其中包括一个成员
ModelA
和一个成员
valueToMap
。提交表单时,我将
modelA
添加到数据库表
modelA
,并创建一个实例并将其添加到
MapToA
,该实例由
modelA
的id和
valueToMap
组成。在代码方面

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
时,它正在工作,但当我编辑它时,它就不工作了

当我试图通过添加
来更改Create.cshtml中的“name”时@Name=“toBeRemoteChecked”…
(而不是由HTML助手创建的
modelA.toBeRemoteChecked
)在
@HTML.TextBoxFor
的htmlAttributes中,则验证正在工作,但值与表的绑定丢失,并且在将值保存到数据库时出现错误(空值)

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

到目前为止,我的解决方法是使
ModelA
CreateModelA
:IValidatableObject
并在我的
public IEnumerable Validate(ValidationContext ValidationContext)
方法中检查成员
以进行远程检查。但是,它会在表单顶部显示错误消息,而不是在TextFor框的位置

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

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

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


谢谢。

这是一个有趣的问题,与之类似,因此我在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]
是一个特定于视图的属性。您应该使用视图模型,尤其是在编辑数据时。(请参阅)

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

远程验证有两种绑定方式,您可以只传递必须进行远程检查的成员

public ActionResult isValid(string toBeRemoteChecked) { ... }
或者可以传递该成员的类的实例

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

如果您有一个非常复杂的模型,您可以通过使用bind/include使用想要使用的成员初始化参数
modelA
,即在我的情况下,我将使用

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

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

谢谢。至于客户端验证,我尝试了inherit选项-也让一个演示项目工作,但是当我
db.ModelAset.Add(createModelA)
时,我要么会自动在数据库中添加不需要的额外列,要么在我手动从数据库中删除这些列后,我会得到一个
无效列名
错误。当我在控制器中手动创建
modelA
时,我可以
db.ModelAset.Add(modelA)
,方法是将所有必需的成员从
createModelA
复制到
modelA
。这有捷径吗?(我的真实模型大约有20名成员,所以这是可能的,但不是很好)。谢谢。你需要再次阅读我的最后一段:)视图模型与数据库没有关系。确定。因此,在移动da时,我需要额外的努力