Asp.net mvc 嵌套对象的远程ViewModel验证不起作用

Asp.net mvc 嵌套对象的远程ViewModel验证不起作用,asp.net-mvc,asp.net-mvc-3,asp.net-mvc-validation,Asp.net Mvc,Asp.net Mvc 3,Asp.net Mvc Validation,我有一个类用户,如下所示: public class User { public int UserId { get; set; } [Required(ErrorMessage = "A username is required.")] [StringLength(20, ErrorMessage = "Your username must be 4-20 characters.", MinimumLength = 4)] [RegularExpression(

我有一个类用户,如下所示:

public class User
{
    public int UserId { get; set; }

    [Required(ErrorMessage = "A username is required.")]
    [StringLength(20, ErrorMessage = "Your username must be 4-20 characters.", MinimumLength = 4)]
    [RegularExpression("^[a-zA-Z0-9]*$", ErrorMessage = "Your username can only consist of letters and numbers.")]
    [Remote("UsernameExists", "RemoteValidation", ErrorMessage = "Username is already taken")]
    public string Username { get; set; }

    [Required(ErrorMessage = "A password is required.")]
    [MinLength(4, ErrorMessage = "Your password must have at least 4 letters.")]
    public string Password { get; set; }

    [Required(ErrorMessage = "An email address is required.")]
    public string Email { get; set; }
}
对于注册功能,我创建了一个ViewModel,其中包含一个用户对象和一个用于密码确认的字符串:

public class RegistrationViewModel
{
    public User User { get; set; }

    [DisplayName("Password confirmation")]
    [Required, Compare("User.Password", ErrorMessage = "The password do not match")]
    public string PasswordConfirmation { get; set; }
}
我遇到的第一个问题是,我似乎无法让比较验证(“User.Password”)工作,因为它似乎找不到用户的属性。是否有方法针对User.Password属性验证PasswordConfirmation属性

第二个问题是用户名字段的远程验证。我在上学习了David Hayden的教程,但是UsernameExists方法中的参数username始终为null。我是不是遗漏了什么

编辑:

很抱歉,实际上我还不太清楚我收到的密码比较错误。它在填写字段时工作正常,如果密码不匹配,我将收到一个错误。但是,在提交表单时,我在验证摘要中遇到以下错误:找不到名为UserToRegister.Password的属性

编辑2:

多亏了乔的帖子,我已经解决了部分问题。远程验证程序发回URL/?UserToRegister.Username=temp,这显然与我的控制器操作的Username参数不匹配。为了将我的操作参数映射到UserToRegister.Username,需要以下参数:

public ActionResult UsernameExists([Bind(Prefix = "UserToRegister.Username")]string username)
这将正确地将参数传递给方法。但是,在密码字段中使用Compare属性时仍然会出现错误


谢谢。

对于远程验证部分,我什么都不知道。打开firebug并查看被激发的请求是什么样子可能会有所帮助。如果一切都正确地连接起来,你应该大致看到这样的东西

http://localhost:14547/[控制器]/[ActionName]?[ParamName]=[paramValue]

根据您提供的请求,您可以使用前缀,就像您最终所做的那样,或者让您的操作使用名为UserToRegister的用户,然后在操作中访问UserName属性。这是处理对象远程验证的推荐方法,可能比使用绑定属性更容易考虑


对于比较验证,客户端验证似乎成功,但服务器端验证失败,因为验证上下文不包含名为User.Password的属性,只有名为User的属性。

在这种情况下,继承似乎是添加功能的标准方法。让您的
RegistrationViewModel
UserViewModel
派生如何:

public class RegistrationViewModel : UserViewModel
{
    [DisplayName("Password confirmation")]
    [Required]
    [Compare("Password", ErrorMessage = "The password do not match")]
    public string PasswordConfirmation { get; set; }
}
以及:


针对User.Password属性验证PasswordConfiguration属性的问题是由“jquery.validate.unobtrusive.js”文件中的错误引起的

最初,jquery“equalTo”函数是:

adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

setValidationValues(options, "equalTo", element);
});
您只需修改此行:

element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
致:


请注意在“fullOtherName”选择器周围的单引号中添加的内容。完成此更改后,客户端验证将按预期工作。

触发的请求如下所示:请求URL:
http://localhost:58777/RemoteValidation/UsernameExists?UserToRegister.Username=temp 它
似乎附加了属性getters作为参数的名称。这是否意味着方法上的my name参数名称应为UserToRegister.Username?这当然不行…谢谢,我会试试的。但肯定有一种方法可以让ViewModel由其他对象组成,而不需要继承。在这个简单的例子中,它可能会起作用,但是如果我有一个地址对象,它使用相同的表单填充呢?我只能从一个用户继承,而不能同时从用户和地址继承。@b3n,通常情况下,如果您有地址,则不需要对地址属性与主视图模型中的某个属性进行
[Compare]
。因此,请尝试正确地设计视图模型。在查看您提供的请求后,我更新了我的答案。您可以让您的操作使用用户而不是字符串来指定前缀。对于compare属性,您需要与模型上的另一个属性进行比较,因此如果您将用户留在模型中,则需要一个返回用户密码的属性,但是你能看看ASP.NET MVC默认模板中的模型吗?这些字段不包含用户本身,但包含来自用户的相关字段,如密码、名称、确认密码等。然后可以使用比较属性来比较这些字段。谢谢Joe,我正在考虑只使用模型上需要的字段,如密码、用户名和电子邮件。但后来我认为它会将验证属性加倍,如果发生变化,我有两个地方可以维护它们。有没有一种干净的方法可以做到这一点(没有继承,因为我的viewmodel将再次包含我不需要的字段)。您可以始终选择一个用户,然后仅将您感兴趣的字段列入该特定操作的白名单/黑名单,也可以创建不同的模型,例如仅包含您感兴趣的用户属性的RegisterModel和LogOnModel,默认项目模板就是这样做的。告诉用户使用了用户名显然是一种安全漏洞。特别是通过一个特殊的“服务”来检查用户名是否被使用。我和询问者有完全相同的问题,这就解决了它。我必须在.js和min.js.BTW中进行替换-我在github中提交了一个bug。我已经告诉了ASP.NET MVC团队这一点,并将找到作者。为了跟进这一点,我刚刚看到了这个页面,我可以看到在最新版本中,通过VS2010中的NuGet添加,这似乎是固定的。
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
element = $(options.form).find(":input[name='" + fullOtherName + "']")[0];