使用多个表单时验证失败
Validation failing when using multiple forms
我正在使用 this construct 在同一视图中托管多个表单:
当我在没有输入凭据的情况下提交第一个表单时,验证失败。表单重新加载为 GET,URL 为 /home/signin
,预期的错误消息不会显示。
控制器的 ModelState
正如预期的那样无效,但我不明白为什么这个状态没有传回视图。
我做错了什么?如何获得验证以使用多个表单?
这是我的代码:
控制器
Imports System.Threading.Tasks
Imports System.Web.Mvc
Imports Website.ViewModels.Home
Imports Microsoft.AspNet.Identity.Owin
Namespace Controllers.Home
Partial Public Class HomeController
<AllowAnonymous>
Public Function Index() As ActionResult
Dim oViewModel As SignInOrSignUp
oViewModel = New SignInOrSignUp
Return Me.View("Index", oViewModel)
End Function
<HttpPost>
<ValidateAntiForgeryToken>
Public Async Function SignIn(Model As SignIn) As Task(Of ActionResult)
Dim oViewModel As SignInOrSignUp
Dim eStatus As SignInStatus
Dim oAction As ActionResult
oViewModel = New SignInOrSignUp With {.SignIn = Model}
If Me.ModelState.IsValid Then
eStatus = Await Me.SignInManager.PasswordSignInAsync(Model.Username, Model.Password, isPersistent:=False, shouldLockout:=False)
If eStatus = SignInStatus.Success Then
oAction = Me.Redirect("www.domain.com")
Else
Me.ModelState.AddModelError("", "Invalid signin attempt.")
oAction = Me.View("Index", oViewModel)
End If
Else
oAction = Me.View("Index", oViewModel)
End If
Return oAction
End Function
End Class
End Namespace
ViewModel
Imports System.ComponentModel.DataAnnotations
Namespace ViewModels.Home
Public Class SignIn
<Required(ErrorMessage:="User Name is required.")>
<Display(Name:="User Name")>
Public Property Username As String
<Required>
Public Property Password As String
<Display(Name:="Remember Me")>
Public Property RememberMe As Boolean
End Class
End Namespace
查看
@ModelType ViewModels.Home.SignInOrSignUp
@Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Website</title>
@Scripts.Render("~/scripts/bootstrap")
@Scripts.Render("~/scripts/jquery")
@Styles.Render("~/styles/bootstrap")
@Styles.Render("~/styles/home")
</head>
<body>
<div class="row">
<div class="wrapper">
<div class="section">
<h5>Sign in here</h5>
<div class="box">
<div class="titlebar">Sign In</div>
@Using (Html.BeginForm("signin", "home", FormMethod.Post, New With {.id = "SignInForm"}))
@Html.AntiForgeryToken
@Html.EditorFor(Function(M) Model.SignIn)
@<div class="button">
<input type="submit" value="Sign In" Class="button" />
</div>
@<div class="anchor">
<a href="/">Forgot your password?</a>
</div>
End Using
</div>
</div>
<div class="section">
<h5>Or enter your City Code here</h5>
<div class="box">
<div class="titlebar">Sign Up</div>
@Using (Html.BeginForm("signup", "home", FormMethod.Post, New With {.id = "SignUpForm"}))
@Html.AntiForgeryToken
@Html.EditorFor(Function(M) Model.SignUp)
@<div class="button">
<input type="submit" value="Continue" Class="button" />
</div>
End Using
</div>
</div>
</div>
</div>
</body>
</html>
--编辑--
在此期间,我已经能够通过笨拙的解决方法畅通无阻:
@Code
If IsPost AndAlso Request.Path = "/home/signin" AndAlso Model.SignIn.Username.IsNothing Then
@Html.ValidationMessageFor(Function(Model) Model.SignIn.Username, "Username is required", New With {.class = "text-danger"})
End If
End Code
但如果可以在同一视图中使用多个表单,我仍然希望使用内置验证机制。
您可以尝试 2 件事:
1.将验证摘要放在页面上:
使用此选项,您不会更改控制器中的任何内容,但会在页面上放置错误摘要。您不会得到突出显示的字段,但您仍然可以显示所有错误,例如:
<body>
<div class="row">
<div class="wrapper">
@Html.ValidationSummary(false)
...
</div>
</div>
</body>
不是一个优雅的解决方案!
2。在控制器中使用 SignInOrSignUp
作为输入,但从 UI 提供 SignIn
或 SignUp
模型:
使用这种方法,您不会更改 vbhtml/cshtml 文件,它将保留下来,因为您唯一要更改的是控制器方法的参数类型:
Namespace Controllers.Home
Partial Public Class HomeController
...
<HttpPost>
<ValidateAntiForgeryToken>
Public Async Function SignIn(Model As SignInOrSignUp) As Task(Of ActionResult)
...
End Function
<HttpPost>
Public Async Function SignUp(Model As SignInOrSignUp) As Task(Of ActionResult)
...
End Function
End Class
End Namespace
除非涉及一些复杂的验证,否则这种方法会很有用!
我正在使用 this construct 在同一视图中托管多个表单:
当我在没有输入凭据的情况下提交第一个表单时,验证失败。表单重新加载为 GET,URL 为 /home/signin
,预期的错误消息不会显示。
控制器的 ModelState
正如预期的那样无效,但我不明白为什么这个状态没有传回视图。
我做错了什么?如何获得验证以使用多个表单?
这是我的代码:
控制器
Imports System.Threading.Tasks
Imports System.Web.Mvc
Imports Website.ViewModels.Home
Imports Microsoft.AspNet.Identity.Owin
Namespace Controllers.Home
Partial Public Class HomeController
<AllowAnonymous>
Public Function Index() As ActionResult
Dim oViewModel As SignInOrSignUp
oViewModel = New SignInOrSignUp
Return Me.View("Index", oViewModel)
End Function
<HttpPost>
<ValidateAntiForgeryToken>
Public Async Function SignIn(Model As SignIn) As Task(Of ActionResult)
Dim oViewModel As SignInOrSignUp
Dim eStatus As SignInStatus
Dim oAction As ActionResult
oViewModel = New SignInOrSignUp With {.SignIn = Model}
If Me.ModelState.IsValid Then
eStatus = Await Me.SignInManager.PasswordSignInAsync(Model.Username, Model.Password, isPersistent:=False, shouldLockout:=False)
If eStatus = SignInStatus.Success Then
oAction = Me.Redirect("www.domain.com")
Else
Me.ModelState.AddModelError("", "Invalid signin attempt.")
oAction = Me.View("Index", oViewModel)
End If
Else
oAction = Me.View("Index", oViewModel)
End If
Return oAction
End Function
End Class
End Namespace
ViewModel
Imports System.ComponentModel.DataAnnotations
Namespace ViewModels.Home
Public Class SignIn
<Required(ErrorMessage:="User Name is required.")>
<Display(Name:="User Name")>
Public Property Username As String
<Required>
Public Property Password As String
<Display(Name:="Remember Me")>
Public Property RememberMe As Boolean
End Class
End Namespace
查看
@ModelType ViewModels.Home.SignInOrSignUp
@Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Website</title>
@Scripts.Render("~/scripts/bootstrap")
@Scripts.Render("~/scripts/jquery")
@Styles.Render("~/styles/bootstrap")
@Styles.Render("~/styles/home")
</head>
<body>
<div class="row">
<div class="wrapper">
<div class="section">
<h5>Sign in here</h5>
<div class="box">
<div class="titlebar">Sign In</div>
@Using (Html.BeginForm("signin", "home", FormMethod.Post, New With {.id = "SignInForm"}))
@Html.AntiForgeryToken
@Html.EditorFor(Function(M) Model.SignIn)
@<div class="button">
<input type="submit" value="Sign In" Class="button" />
</div>
@<div class="anchor">
<a href="/">Forgot your password?</a>
</div>
End Using
</div>
</div>
<div class="section">
<h5>Or enter your City Code here</h5>
<div class="box">
<div class="titlebar">Sign Up</div>
@Using (Html.BeginForm("signup", "home", FormMethod.Post, New With {.id = "SignUpForm"}))
@Html.AntiForgeryToken
@Html.EditorFor(Function(M) Model.SignUp)
@<div class="button">
<input type="submit" value="Continue" Class="button" />
</div>
End Using
</div>
</div>
</div>
</div>
</body>
</html>
--编辑--
在此期间,我已经能够通过笨拙的解决方法畅通无阻:
@Code
If IsPost AndAlso Request.Path = "/home/signin" AndAlso Model.SignIn.Username.IsNothing Then
@Html.ValidationMessageFor(Function(Model) Model.SignIn.Username, "Username is required", New With {.class = "text-danger"})
End If
End Code
但如果可以在同一视图中使用多个表单,我仍然希望使用内置验证机制。
您可以尝试 2 件事:
1.将验证摘要放在页面上:
使用此选项,您不会更改控制器中的任何内容,但会在页面上放置错误摘要。您不会得到突出显示的字段,但您仍然可以显示所有错误,例如:
<body>
<div class="row">
<div class="wrapper">
@Html.ValidationSummary(false)
...
</div>
</div>
</body>
不是一个优雅的解决方案!
2。在控制器中使用 SignInOrSignUp
作为输入,但从 UI 提供 SignIn
或 SignUp
模型:
使用这种方法,您不会更改 vbhtml/cshtml 文件,它将保留下来,因为您唯一要更改的是控制器方法的参数类型:
Namespace Controllers.Home
Partial Public Class HomeController
...
<HttpPost>
<ValidateAntiForgeryToken>
Public Async Function SignIn(Model As SignInOrSignUp) As Task(Of ActionResult)
...
End Function
<HttpPost>
Public Async Function SignUp(Model As SignInOrSignUp) As Task(Of ActionResult)
...
End Function
End Class
End Namespace
除非涉及一些复杂的验证,否则这种方法会很有用!