使用多种表单时验证失败 [英] Validation failing when using multiple forms
问题描述
我正在使用
当我在不输入凭据的情况下提交第一份表格时,验证失败.表单以GET的形式重新加载,URL为/home/signin
,并且不会显示预期的错误消息.
控制器的 ModelState
无效,但我无法弄清楚为什么这种状态没有传递回视图.
我做错了什么?如何获得可用于多种表单的验证?
这是我的代码:
控制器
导入System.Threading.Tasks导入System.Web.Mvc导入Website.ViewModels.Home导入Microsoft.AspNet.Identity.Owin命名空间控制器部分公共类HomeController< AllowAnonymous>公共功能Index()作为ActionResultDim oViewModel作为SignInOrSignUpoViewModel =新SignInOrSignUp返回Me.View("Index",oViewModel)结束功能< HttpPost>< ValidateAntiForgeryToken>公共异步函数登录(作为登录模型)作为任务(作为动作结果)Dim oViewModel作为SignInOrSignUpDim eStatus作为SignInStatusDim oAction作为ActionResultoViewModel =带有{.SignIn = Model}的新SignInOrSignUp如果Me.ModelState.IsValid然后eStatus =等待我.SignInManager.PasswordSignInAsync(Model.Username,Model.Password,isPersistent:= False,shouldLockout:= False)如果eStatus = SignInStatus.Success然后oAction = Me.Redirect("www.domain.com")别的Me.ModelState.AddModelError(",无效的登录尝试".)oAction = Me.View("Index",oViewModel)万一别的oAction = Me.View("Index",oViewModel)万一返回oAction结束功能末级结束命名空间
ViewModel
导入System.ComponentModel.DataAnnotations命名空间ViewModels.Home公开课登录< Required(ErrorMessage:="需要用户名.")>< Display(Name:="用户名")>公共属性用户名作为字符串<必需>公共属性密码为字符串< Display(Name:=" Remember Me")>公共属性"RememberMe"为布尔型末级结束命名空间
查看
@ModelType ViewModels.Home.SignInOrSignUp@代码布局=什么都没有结束码<!DOCTYPE html>< html>< head><元字符集="utf-8";/><元名称=视口"内容=宽度=设备宽度,初始比例= 1.0."< title>网站</title>@ Scripts.Render(〜/scripts/bootstrap")@ Scripts.Render(〜/scripts/jquery")@ Styles.Render(〜/styles/bootstrap")@ Styles.Render(〜/styles/home")</head><身体>< div class ="row">< div class =包装器">< div class ="section">< h5>在此处登录</h5>< div class ="box">< div class =标题栏">登录</div>@使用(Html.BeginForm("signin","home",FormMethod.Post,{.id ="SignInForm"}新建的)))@ Html.AntiForgeryToken@ HTML.EditorFor(功能(M)模型.登录)@< div class ="button"><输入类型=提交";value =登录"Class ="button"/></div>@< div class ="anchor">< a href ="/">忘记密码了吗?</a></div>最终使用</div></div>< div class ="section">< h5>或在此处输入您的城市代码</h5>< div class ="box">< div class =标题栏">注册</div>@使用(Html.BeginForm("signup","home",FormMethod.Post,{.id ="SignUpForm"}}的新内容))@ Html.AntiForgeryToken@ HTML.EditorFor(功能(M)模型.SignUp)@< div class ="button"><输入类型=提交";value ="Continue"Class ="button"/></div>最终使用</div></div></div></div></body></html>
-编辑-
在此期间,我已经能够通过笨拙的解决方法不受阻碍:
@Code如果IsPost AndAlso Request.Path ="/home/signin",还有Model.SignIn.Username.Isthing然后@ Html.ValidationMessageFor(Function(Model)Model.SignIn.Username,需要用户名",新的{.class ="text-danger"})万一结束码
但是我仍然想使用内置的验证机制,如果有可能在同一个视图中使用多种形式的话.
您可以尝试以下两种方法:
1.在页面上放入验证摘要:
使用此选项,您无需更改控制器中的任何内容,但可以在页面上显示错误摘要.您将不会看到突出显示的字段,但仍然可以显示所有错误,例如:
< body>< div class ="row">< div class =包装器">@ Html.ValidationSummary(false)...</div></div></body>
这不是一个优雅的解决方案!
2.在控制器中,使用 SignInOrSignUp
作为输入,但从用户界面提供 SignIn
或 SignUp
模型:
使用这种方法,您无需更改vbhtml/cshtml文件,因为在控制器方法上的参数类型只是您要更改的地方,它仍将保留:
命名空间Controllers.Home部分公共类HomeController...< HttpPost>< ValidateAntiForgeryToken>公共异步函数SignIn(模型为SignInOrSignUp)作为Task(动作结果)...结束功能< HttpPost>公共异步函数注册(模型为SignInOrSignUp)作为任务(ActionResult的)...结束功能末级结束命名空间
除非涉及到一些复杂的验证,否则此方法将像魅力一样发挥作用!
I'm using this construct to host multiple forms in the same view:
When I submit the first form without entering credentials, validation fails. The form reloads as a GET, with a URL of /home/signin
, and the expected error messages don't display.
The controller's ModelState
is invalid as expected, but I can't figure out why this state isn't passed back to the view.
What am I doing wrong? How can I get validation to work with multiple forms?
Here's my code:
Controller
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
View
@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>
--EDIT--
I've been able to get unblocked in the meantime with a clunky workaround in my view:
@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
But I'd still like to use the in-built validation mechanism if it's possible to do so with multiple forms in the same view.
There are 2 things you can try:
1. Put validation summary on the page:
With this option you are not changing anything in your controller but you are putting error summary on your page. You will not get highlighted field but you will still be able to display all errors, like:
<body>
<div class="row">
<div class="wrapper">
@Html.ValidationSummary(false)
...
</div>
</div>
</body>
Not an elegant solution!
2. In controller use SignInOrSignUp
as an input but from UI provide either SignIn
or SignUp
model:
With this approach you are not changing your vbhtml/cshtml file it will remain as it is only thing you are changing is type of argument on controller methods:
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
unless there is some complex validation involved, this approach will work like a charm!
这篇关于使用多种表单时验证失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!