【问题标题】:Remote ViewModel validation of nested objects not working嵌套对象的远程 ViewModel 验证不起作用
【发布时间】:2011-06-28 18:15:06
【问题描述】:

我有一个类用户,看起来像这样:

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; }
}

我遇到的第一个问题是我似乎无法验证 Compare("User.Password") 的工作,因为它似乎没有找到用户的属性。有什么方法可以根据 User.Password 属性验证 PasswordConfirmation 属性吗?

第二个问题是用户名字段的远程验证。我在 http://davidhayden.com/blog/dave/archive/2011/01/04/ASPNETMVC3RemoteValidationTutorial.aspx 上按照 David Hayden 的教程进行操作,但 UsernameExists 方法中的参数 username 始终为空。我在这里遗漏了什么吗?

编辑:

很抱歉,我实际上并不清楚我收到的密码比较错误。填写字段时效果很好,如果密码不匹配,我将收到错误消息。但是,在提交表单时,我在验证摘要中收到以下错误:找不到名为 UserToRegister.Password 的属性。

编辑 2:

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

public ActionResult UsernameExists([Bind(Prefix = "UserToRegister.Username")]string username)

现在可以正确地将参数传递给方法。但是,在密码字段上使用比较属性时,我仍然会收到错误消息。

谢谢。

【问题讨论】:

  • 查看您提供的请求后,我更新了答案。您可以使您的操作采用用户而不是字符串来解决指定前缀的问题。
  • 对于 compare 属性,您需要与模型上的另一个属性进行比较,因此如果您将用户留在模型中,您将需要一个返回用户密码的属性,但是您可以采取看看 ASP.NET MVC 默认模板中的模型?这些不包含用户本身,而是来自用户的相关字段,例如密码、姓名、确认密码等。然后可以使用 compare 属性来比较这些字段。
  • 谢谢乔,我想只使用模型上我需要的字段,例如密码、用户名和电子邮件。但后来我认为它会使验证属性加倍,如果发生变化,我有两个地方可以维护它们。有没有一种干净的方法来做到这一点(没有继承,因为我的视图模型将再次包含我不需要的字段)。
  • 您可以始终获取用户,然后仅将您对该特定操作感兴趣的字段列入白名单/黑名单,或者您可以创建不同的模型,例如仅包含以下属性的 RegisterModel 和 LogOnModel您感兴趣的用户,这是默认项目模板所做的。
  • 告诉用户用户名已被使用是明显的安全漏洞。尤其是通过一个特殊的“服务”来检查用户名是否被使用。

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-validation


【解决方案1】:

根据 User.Password 属性验证 PasswordConfigurmation 属性的问题是由“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];

到:

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

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

【讨论】:

  • 我遇到了和提问者完全相同的问题,这解决了它。我必须在 .js 和 min.js 中进行替换。
  • 顺便说一句 - 我在 github 中提交了一个错误。 github.com/jzaefferer/jquery-validation/issues/327
  • 我已经把这件事告诉了 ASP.NET MVC 团队,我会找到作者的。
  • 只是为了跟进,我刚刚看到这个页面,我可以看到在最新版本中,通过 NuGet 在 VS2010 中添加,这似乎已修复。
【解决方案2】:

对于远程验证部分,我没有任何反应。打开 firebug 并查看正在触发的请求可能会有所帮助。如果一切都正确连接,你应该会看到大致这样的东西......

http://localhost:14547/[Controller]/[ActionName]?[ParamName]=[paramValue]

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

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

【讨论】:

  • 触发的请求如下所示: Request URL:http://localhost:58777/RemoteValidation/UsernameExists?UserToRegister.Username=temp it 似乎它附加了属性 getter 作为参数的名称。这是否意味着我在方法上的名称参数名称应该是 UserToRegister.Username?这当然行不通……
【解决方案3】:

在这种情况下,继承似乎是一种添加功能的标准方式。让您的RegistrationViewModel 派生自UserViewModel 怎么样:

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

和:

public ActionResult UsernameExists(string Username)
{
   ...
}

【讨论】:

  • 谢谢,我试试看。但是肯定有一种方法可以让 ViewModel 由其他没有继承的对象组成。在这个简单的情况下,它可能会起作用,但是如果我有一个使用相同表单填充的 Address 对象呢?我只能从一个继承,而不是同时继承用户和地址。
  • @b3n,通常如果你有地址,你不需要在主视图模型上的某个属性的地址属性上执行[Compare]。因此,请尝试正确设计您的视图模型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
  • 2012-01-09
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多