如何在不返回 asp.net 中的视图的情况下验证表单?
How to validate a form without returning a view in asp.net?
我制作了一个下拉菜单,用户可以在其中从导航栏登录,而不是按登录按钮并被重定向到 account/login。这是在局部视图中完成的,并在 _layout.cshtml 的导航栏中呈现。部分视图如下所示:
´´´
@using Microsoft.AspNet.Identity
@model Rent_a_Car.Models.LoginViewModel
@{
if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@User.Identity.GetUserName()
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
@Html.ActionLink("My account", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage", @class = "dropdown-item" })
<a class="dropdown-item disabled" href="#">My orders</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
</div>
</div>
<li></li>
</ul>
}
}
else
{
<div class="dropleft">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Log-In </button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" style="width: 300px">
@* form starting *@
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="col-lg-12">
<div class="text-center">
<h3><b>Log In</b></h3>
</div>
<form id="ajax-login-form" method="post" role="form" autocomplete="off">
<div class="form-group">
<label for="username">Username</label>
@Html.TextBoxFor(m => m.Email, new { @class = "form-control", @placeholder = "Email" })
</div>
<div class="form-group">
<label for="password">Password</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" })
</div>
<div class="form-group">
<div class="col-xs-5">
<input type="submit" name="Login" id="login-submit" tabindex="4" class="form-control btn btn-danger" value="Log In">
</div>
</div>
<div class="col-xs-5" align="Center">
@Html.CheckBoxFor(m => m.RememberMe)
<label for="remember"> Remember Me</label>
</div>
<div class="form-group">
<div class="row">
<div class="col-lg-12">
<div class="text-center">
<a tabindex="5" class="forgot-password">Forgot Password?</a>
</div>
</div>
</div>
</div>
</form>
</div>
}
@*form ending*@
</div>
</div>
}
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
´´´
这是控制器。如您所见,当验证失败时,我将返回模型,这是我不想要的。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
我只需要验证错误消息出现在下拉菜单中,而不需要将我重定向到另一个页面。我怎样才能做到这一点?
其他人问的大问题是为什么不使用 javascript 调用 api 进行登录,例如使用 ajax post
$.post("your api here",
{
userName: "",
password: "",
rememberMe: ""
},function(data, status){
//show user what ever
});
这段代码很简单,但是如果你不能使用 javascript 因为什么 "I wouldn't know" 你将有下面的长代码和你现有控制器上的一些实现
我会一一解释
您必须在表单中添加 ReturnUrl
,将您的登录表单更改为此
@using Microsoft.AspNet.Identity
@model Rent_a_Car.Models.LoginViewModel
@{
if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", new { returnUrl = Request.Url.PathAndQuery }, FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@User.Identity.GetUserName()
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
@Html.ActionLink("My account", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage", @class = "dropdown-item" })
<a class="dropdown-item disabled" href="#">My orders</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
</div>
</div>
</ul>
}
}
else
{
<div class="dropleft">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Log-In </button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" style="width: 300px">
@* form starting *@
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<p>@ViewBag.error</p>@*Display the error here*@
<div class="col-lg-12">
<div class="text-center">
<h3><b>Log In</b></h3>
</div>
<form id="ajax-login-form" method="post" role="form" autocomplete="off">
<div class="form-group">
<label for="username">Username</label>
@Html.TextBoxFor(m => m.Email, new { @class = "form-control", @placeholder = "Email" })
</div>
<div class="form-group">
<label for="password">Password</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" })
</div>
<div class="form-group">
<div class="col-xs-5">
<input type="submit" name="Login" id="login-submit" tabindex="4" class="form-control btn btn-danger" value="Log In">
</div>
</div>
<div class="col-xs-5" align="Center">
@Html.CheckBoxFor(m => m.RememberMe)
<label for="remember"> Remember Me</label>
</div>
<div class="form-group">
<div class="row">
<div class="col-lg-12">
<div class="text-center">
<a tabindex="5" class="forgot-password">Forgot Password?</a>
</div>
</div>
</div>
</div>
</form>
</div>
}
@*form ending*@
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
然后在你的 Account Controller
, return 中重定向到用户当前所在的视图,因为它是重定向,你必须将你的模型放入 TempData
这就是为什么 @Html.ValidationSummary(true, "", new { @class = "text-danger" })
和其他一些模型错误可能对您不起作用,所以您自己进行验证。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
//here send back the error and the model with validation message to any view
TempData["LoginModel"] = model;
TempData["LoginError"] = "Incorrect details";
return Redirect(returnUrl);
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
TempData["LoginModel"] = model;
TempData["LoginError"] = "Invalid login attempt";
return Redirect(returnUrl);
}
}
现在你有很多事情要做。
您需要找到用户可能首先点击的所有可能的控制器(我会建议您所有的控制器)并获取 TempData
(模型)和错误。例如,CarController
的 Index
方法可以是:
public ActionResult Index(int Id)
{
LoginViewModel model = (LoginViewModel) TempData["LoginModel"];
ViewBag.error = TempData["LoginError"];
//Do other logic
return View(model);
}
我制作了一个下拉菜单,用户可以在其中从导航栏登录,而不是按登录按钮并被重定向到 account/login。这是在局部视图中完成的,并在 _layout.cshtml 的导航栏中呈现。部分视图如下所示:
´´´
@using Microsoft.AspNet.Identity
@model Rent_a_Car.Models.LoginViewModel
@{
if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@User.Identity.GetUserName()
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
@Html.ActionLink("My account", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage", @class = "dropdown-item" })
<a class="dropdown-item disabled" href="#">My orders</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
</div>
</div>
<li></li>
</ul>
}
}
else
{
<div class="dropleft">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Log-In </button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" style="width: 300px">
@* form starting *@
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="col-lg-12">
<div class="text-center">
<h3><b>Log In</b></h3>
</div>
<form id="ajax-login-form" method="post" role="form" autocomplete="off">
<div class="form-group">
<label for="username">Username</label>
@Html.TextBoxFor(m => m.Email, new { @class = "form-control", @placeholder = "Email" })
</div>
<div class="form-group">
<label for="password">Password</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" })
</div>
<div class="form-group">
<div class="col-xs-5">
<input type="submit" name="Login" id="login-submit" tabindex="4" class="form-control btn btn-danger" value="Log In">
</div>
</div>
<div class="col-xs-5" align="Center">
@Html.CheckBoxFor(m => m.RememberMe)
<label for="remember"> Remember Me</label>
</div>
<div class="form-group">
<div class="row">
<div class="col-lg-12">
<div class="text-center">
<a tabindex="5" class="forgot-password">Forgot Password?</a>
</div>
</div>
</div>
</div>
</form>
</div>
}
@*form ending*@
</div>
</div>
}
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
´´´
这是控制器。如您所见,当验证失败时,我将返回模型,这是我不想要的。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
我只需要验证错误消息出现在下拉菜单中,而不需要将我重定向到另一个页面。我怎样才能做到这一点?
其他人问的大问题是为什么不使用 javascript 调用 api 进行登录,例如使用 ajax post
$.post("your api here",
{
userName: "",
password: "",
rememberMe: ""
},function(data, status){
//show user what ever
});
这段代码很简单,但是如果你不能使用 javascript 因为什么 "I wouldn't know" 你将有下面的长代码和你现有控制器上的一些实现
我会一一解释
您必须在表单中添加 ReturnUrl
,将您的登录表单更改为此
@using Microsoft.AspNet.Identity
@model Rent_a_Car.Models.LoginViewModel
@{
if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", new { returnUrl = Request.Url.PathAndQuery }, FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@User.Identity.GetUserName()
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
@Html.ActionLink("My account", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage", @class = "dropdown-item" })
<a class="dropdown-item disabled" href="#">My orders</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
</div>
</div>
</ul>
}
}
else
{
<div class="dropleft">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Log-In </button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" style="width: 300px">
@* form starting *@
@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<p>@ViewBag.error</p>@*Display the error here*@
<div class="col-lg-12">
<div class="text-center">
<h3><b>Log In</b></h3>
</div>
<form id="ajax-login-form" method="post" role="form" autocomplete="off">
<div class="form-group">
<label for="username">Username</label>
@Html.TextBoxFor(m => m.Email, new { @class = "form-control", @placeholder = "Email" })
</div>
<div class="form-group">
<label for="password">Password</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" })
</div>
<div class="form-group">
<div class="col-xs-5">
<input type="submit" name="Login" id="login-submit" tabindex="4" class="form-control btn btn-danger" value="Log In">
</div>
</div>
<div class="col-xs-5" align="Center">
@Html.CheckBoxFor(m => m.RememberMe)
<label for="remember"> Remember Me</label>
</div>
<div class="form-group">
<div class="row">
<div class="col-lg-12">
<div class="text-center">
<a tabindex="5" class="forgot-password">Forgot Password?</a>
</div>
</div>
</div>
</div>
</form>
</div>
}
@*form ending*@
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
然后在你的 Account Controller
, return 中重定向到用户当前所在的视图,因为它是重定向,你必须将你的模型放入 TempData
这就是为什么 @Html.ValidationSummary(true, "", new { @class = "text-danger" })
和其他一些模型错误可能对您不起作用,所以您自己进行验证。
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
//here send back the error and the model with validation message to any view
TempData["LoginModel"] = model;
TempData["LoginError"] = "Incorrect details";
return Redirect(returnUrl);
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
TempData["LoginModel"] = model;
TempData["LoginError"] = "Invalid login attempt";
return Redirect(returnUrl);
}
}
现在你有很多事情要做。
您需要找到用户可能首先点击的所有可能的控制器(我会建议您所有的控制器)并获取 TempData
(模型)和错误。例如,CarController
的 Index
方法可以是:
public ActionResult Index(int Id)
{
LoginViewModel model = (LoginViewModel) TempData["LoginModel"];
ViewBag.error = TempData["LoginError"];
//Do other logic
return View(model);
}