Asp.net mvc 使用uu RequestVerificationToken对嵌套视图模型进行远程验证

Asp.net mvc 使用uu RequestVerificationToken对嵌套视图模型进行远程验证,asp.net-mvc,antiforgerytoken,remote-validation,Asp.net Mvc,Antiforgerytoken,Remote Validation,我有一个名为“LoginIndexViewModel”的viewmodel类,用于登录页面,包含登录、登录和忘记密码表单。它包含多个属性,每个属性分别是一个viewmodel。以下是“LoginIndexViewModel”视图模型: public class LoginIndexViewModel { public LoginViewModel Login { get; set; } public SignUpViewModel SignUp { get; set; }

我有一个名为“LoginIndexViewModel”的viewmodel类,用于登录页面,包含登录、登录和忘记密码表单。它包含多个属性,每个属性分别是一个viewmodel。以下是“LoginIndexViewModel”视图模型:

public class LoginIndexViewModel
{
    public LoginViewModel Login { get; set; }

    public SignUpViewModel SignUp { get; set; }

    public ForgetPasswordViewModel ForgetPassword { get; set; }
}
在“SignUpViewModel”中,有一个属性具有远程验证,我想在调用操作方法之前检查防伪令牌。以下是“SignUpViewModel”的主体:

我在razor视图的操作方法“CheckUsername”和@Html.AntiForgeryToken()上使用了[ValidateAntiForgeryToken]属性,如下所示:

[HttpPost]
[AjaxOnly]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public virtual async Task<JsonResult> CheckUsername([Bind(Prefix = "SignUp.UserName")]string userName)
{
    return Json(await _userManager.CheckUsername(username), JsonRequestBehavior.AllowGet);
}
[HttpPost]
[仅限AjaxOnly]
[异名]
[ValidateAntiForgeryToken]
[OutputCache(Location=OutputCacheLocation.None,NoStore=true)]
公共虚拟异步任务检查用户名([Bind(Prefix=“SignUp.UserName”)]字符串用户名)
{
返回Json(wait _userManager.CheckUsername(username),JsonRequestBehavior.AllowGet);
}
razor视图:

 @using (Html.BeginForm(MVC.Account.ActionNames.Register, MVC.Account.Name, FormMethod.Post, new { id = "RegisterForm", @class = "m-login__form m-form", role = "form" }))
 {
   @Html.AntiForgeryToken()
   .
   .
   .
   <div class="form-group">
       @Html.TextBoxFor(m => m.SignUp.UserName, new { @class = "form-control", placeholder = "Email *", autocomplete = "off", @Value = "" })
       <span class="helper">@Html.ValidationMessageFor(model => model.SignUp.UserName)</span>
   </div>
   .
   .
   .
 }
@使用(Html.BeginForm(MVC.Account.ActionNames.Register、MVC.Account.Name、FormMethod.Post、new{id=“RegisterForm”、@class=“m-login\u form m-form”、role=“form”}))
{
@Html.AntiForgeryToken()
.
.
.
@Html.TextBoxFor(m=>m.SignUp.UserName,新的{@class=“form control”,placeholder=“Email*”,autocomplete=“off”,“@Value=”“})
@Html.ValidationMessageFor(model=>model.SignUp.UserName)
.
.
.
}
问题是远程验证调用引发异常:所需的防伪表单字段“\uu RequestVerificationToken”不存在。

根据Mozilla调试器工具,我发现CheckUsername调用的参数是“SignUp.\uuu RequestVerificationToken”而不是“uuuu RequestVerificationToken”,因此会引发异常


任何人都知道发生了什么以及为什么uu RequestVerificationToken没有提供?

将前缀添加到
AdditionalFields
中定义的属性是经过设计的,并且是由
jquery.validate.unobtrusive.js
添加的。添加前缀的相关代码位于
适配器中。add(“remote”、[“url”、“type”、“additionalfields”]、function(options){
方法

有很多方法可以解决你的问题

基于现有源代码创建您自己的自定义(例如)
[ValidateAntiForgeryTokenWithPrefix]
属性,但修改以从请求中删除任何前缀(不推荐)

进行您自己的ajax调用,而不是使用
[Remote]
属性,即处理文本框的
.blur()
事件来调用服务器方法,传递值和令牌,并更新成功回调中由
@Html.ValidationMessageFor()
生成的占位符,并处理
.keyup()
事件以清除任何消息。这确实具有性能优势,因为在初始验证之后,
远程
规则会对每个
keyup()
事件进行ajax调用,因此可能会导致大量服务器和数据库调用

然而,最简单的解决方案是基于
LoginViewModel
SignUpViewModel
ForgetPasswordViewModel
创建3个部分,然后使用
@Html.Partial()
从主视图调用

_SignUpViewModel.cshtml

@model SignUpViewModel
....
@using (Html.BeginForm(MVC.Account.ActionNames.Register, MVC.Account.Name, FormMethod.Post, new { id = "RegisterForm", @class = "m-login__form m-form", role = "form" }))
{
    @Html.AntiForgeryToken()
    ....
    <div class="form-group">
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", placeholder = "Email *", autocomplete = "off" })
        <span class="helper">
            @Html.ValidationMessageFor(model => model.UserName)
        </span>
    </div>
    ....
}
然后可以从
CheckUsername()
方法中省略
[Bind(Prefix=“SignUp.UserName”)]

或者,您可以基于say
LoginViewModel
创建主视图,然后使用
@Html.Action()
调用
[ChildActionOnly]
方法,返回其他两个表单的部分视图

话虽如此,用户只会使用
注册
表单一次,并且可能永远不会使用
伪造密码
表单,因此包含所有额外的html只会降低性能,最好有链接将它们重定向到
注册
伪造密码
的单独页面,或者如果您想要我在同一个页面中,然后使用ajax根据需要为它们加载部分

作为补充说明,在
返回Json(…)
(它是
[HttpPost]
方法)中不需要
JsonRequestBehavior.AllowGet
参数,并且在使用
HtmlHelper
方法时不应该设置
属性

@model SignUpViewModel
....
@using (Html.BeginForm(MVC.Account.ActionNames.Register, MVC.Account.Name, FormMethod.Post, new { id = "RegisterForm", @class = "m-login__form m-form", role = "form" }))
{
    @Html.AntiForgeryToken()
    ....
    <div class="form-group">
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", placeholder = "Email *", autocomplete = "off" })
        <span class="helper">
            @Html.ValidationMessageFor(model => model.UserName)
        </span>
    </div>
    ....
}
@model LoginIndexViewModel
....
@Html.Partial("_SignUpViewModel", Model.SignUp)
.... // ditto for Login and ForgetPassword properties