一个视图中的多个模型 - 使用 ViewModel 登录和注册 - 具有字段和 ModelState 验证
Multiple models in one view - login & register using ViewModel - with field & ModelState validation
我有一个 MVC 5 应用程序,它在一个视图中使用多个模型进行登录和注册。在 Google 和 Stack Overflow returns 上搜索许多关于如何实现它的例子。这个例子部分有效。但是,我在验证方面遇到了问题,而且我似乎找不到一个明确的例子。如果我在没有在字段中输入任何值的情况下单击登录表单,我总是得到一个空引用并且我的 ModelState 始终有效!
我的登录模型:
public class LoginModel
{
[Required(ErrorMessage = "Please enter a valid username.")]
public string txtUsername { get; set; }
[Required(ErrorMessage = "The password field is required.")]
public string txtPassword { get; set; }
}
我的注册模型:
public class RegisterModel
{
[Required(ErrorMessage = "Please enter a first name.")]
public string txtFirstName { get; set; }
[Required(ErrorMessage = "Please enter a last name.")]
public string txtLastName { get; set; }
}
我的视图模型:
public class ViewModelVM
{
public LoginModel loginModel { get; set; }
public RegisterModel registerModel { get; set; }
}
我的家庭控制器提交并注册操作:
[HttpPost]
public ActionResult LoginSubmit(ViewModelVM vm)
{
if (ModelState.IsValid)
{
//perform other logic.
return View("Index");
}
else
{
return View("Login", vm.loginModel);
}
}
[HttpPost]
public ActionResult RegisterSubmit(ViewModelVM vm)
{
if (ModelState.IsValid)
{
return View("Index");
}
else
{
return View("Login", vm);
}
}
我的看法:
@model MVCTemplate.ViewModel.ViewModelVM
@{
ViewBag.Title = "Login & Register";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="col-lg-10 mx-auto">
@using (Html.BeginForm("LoginSubmit", "Home", FormMethod.Post))
{
<div id="loginForm" class="p-5">
<div class="form-group">
@Html.Label("Username", new { @class = "labeltiny" })
@Html.TextBox("txtUserName", "", new { @class = "form-control", @PlaceHolder = "Username" })
@Html.ValidationMessageFor(x => x.loginModel.txtUsername, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
@Html.Label("Password", new { @class = "labeltiny" })
@Html.Password("txtPassword", "", new { @class = "form-control", @PlaceHolder = "Password" })
@Html.ValidationMessageFor(x => x.loginModel.txtPassword, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
<div class="row">
<div class="col-md-12 text-center">
<input type="submit" name="btnLogin" id="btnLogin" tabindex="4" class="form-control btn btn-login" value="Log In" onclick="sweetalertSpinner()">
</div>
</div>
</div>
</div>
}
@using (Html.BeginForm("RegisterSubmit", "Home", FormMethod.Post))
{
<div id="registerForm" class="p-5" style="display: none">
<div class="form-group">
@Html.Label("First Name", new { @class = "labeltiny" })
@Html.TextBox("txtFirstName", "", new { @class = "form-control", @PlaceHolder = "Fist Name" })
@Html.ValidationMessageFor(x => x.registerModel.txtFirstName, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
@Html.Label("Last Name", new { @class = "labeltiny" })
@Html.Password("txtLastName", "", new { @class = "form-control", @PlaceHolder = "Last Name" })
@Html.ValidationMessageFor(x => x.registerModel.txtLastName, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
<div class="row">
<div class="col-md-12 text-center">
<input type="submit" name="btnRegister" id="btnRegister" tabindex="4" class="form-control btn btn-login" value="Register" onclick="sweetalertSpinner()">
</div>
</div>
</div>
</div>
}
</div>
正如 docs 所说:“模型状态表示来自两个子系统的错误:模型绑定和模型验证。”
ModelState
将仅表示一个模型,并且由于您正在定义视图模型
public class ViewModelVM
{
public LoginModel loginModel { get; set; }
public RegisterModel registerModel { get; set; }
}
然后模型绑定和模型验证将基于 ViewModelVM
的属性而不是它的对象中的属性,这就是为什么你会得到 ModelState.IsValid == true
我认为你可以使用的是每个模型的手动验证,here你可以找到一种方法。
或许您可以创建一个 class 并继承您想要的两个模型,但我不确定这是否可行。如果您尝试过,请告诉我们。
我找到了似乎是解决方案的方法。
将以下内容添加到 ViewModel
public class ViewModelVM
{
public LoginModel loginModel { get; set; }
public RegisterModel registerModel { get; set; }
public string txtUsername { get; set; }
public string txtPassword { get; set; }
public string txtFirstName { get; set; }
public string txtLastName { get; set; }
}
按如下方式更改每个表单域的视图(删除对 loginModel
和 registerModel
的引用):
@Html.ValidationMessageFor(x => x.txtUsername, "", new { @class = "text-danger labeltiny" })
像这样在控制器中将 LoginModel 作为参数而不是 ViewModelVM 传递(对 RegisterSubmit 执行相同操作):
[HttpPost]
public ActionResult LoginSubmit(LoginModel lm)
{
ViewModelVM vm = new ViewModelVM();
if (ModelState.IsValid)
{
//perform other logic using form fields lm.txtUsername, etc...
return View("Index");
}
else
{
return View("Login", vm);
}
}
我有一个 MVC 5 应用程序,它在一个视图中使用多个模型进行登录和注册。在 Google 和 Stack Overflow returns 上搜索许多关于如何实现它的例子。这个例子部分有效。但是,我在验证方面遇到了问题,而且我似乎找不到一个明确的例子。如果我在没有在字段中输入任何值的情况下单击登录表单,我总是得到一个空引用并且我的 ModelState 始终有效!
我的登录模型:
public class LoginModel
{
[Required(ErrorMessage = "Please enter a valid username.")]
public string txtUsername { get; set; }
[Required(ErrorMessage = "The password field is required.")]
public string txtPassword { get; set; }
}
我的注册模型:
public class RegisterModel
{
[Required(ErrorMessage = "Please enter a first name.")]
public string txtFirstName { get; set; }
[Required(ErrorMessage = "Please enter a last name.")]
public string txtLastName { get; set; }
}
我的视图模型:
public class ViewModelVM
{
public LoginModel loginModel { get; set; }
public RegisterModel registerModel { get; set; }
}
我的家庭控制器提交并注册操作:
[HttpPost]
public ActionResult LoginSubmit(ViewModelVM vm)
{
if (ModelState.IsValid)
{
//perform other logic.
return View("Index");
}
else
{
return View("Login", vm.loginModel);
}
}
[HttpPost]
public ActionResult RegisterSubmit(ViewModelVM vm)
{
if (ModelState.IsValid)
{
return View("Index");
}
else
{
return View("Login", vm);
}
}
我的看法:
@model MVCTemplate.ViewModel.ViewModelVM
@{
ViewBag.Title = "Login & Register";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="col-lg-10 mx-auto">
@using (Html.BeginForm("LoginSubmit", "Home", FormMethod.Post))
{
<div id="loginForm" class="p-5">
<div class="form-group">
@Html.Label("Username", new { @class = "labeltiny" })
@Html.TextBox("txtUserName", "", new { @class = "form-control", @PlaceHolder = "Username" })
@Html.ValidationMessageFor(x => x.loginModel.txtUsername, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
@Html.Label("Password", new { @class = "labeltiny" })
@Html.Password("txtPassword", "", new { @class = "form-control", @PlaceHolder = "Password" })
@Html.ValidationMessageFor(x => x.loginModel.txtPassword, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
<div class="row">
<div class="col-md-12 text-center">
<input type="submit" name="btnLogin" id="btnLogin" tabindex="4" class="form-control btn btn-login" value="Log In" onclick="sweetalertSpinner()">
</div>
</div>
</div>
</div>
}
@using (Html.BeginForm("RegisterSubmit", "Home", FormMethod.Post))
{
<div id="registerForm" class="p-5" style="display: none">
<div class="form-group">
@Html.Label("First Name", new { @class = "labeltiny" })
@Html.TextBox("txtFirstName", "", new { @class = "form-control", @PlaceHolder = "Fist Name" })
@Html.ValidationMessageFor(x => x.registerModel.txtFirstName, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
@Html.Label("Last Name", new { @class = "labeltiny" })
@Html.Password("txtLastName", "", new { @class = "form-control", @PlaceHolder = "Last Name" })
@Html.ValidationMessageFor(x => x.registerModel.txtLastName, "", new { @class = "text-danger labeltiny" })
</div>
<div class="form-group">
<div class="row">
<div class="col-md-12 text-center">
<input type="submit" name="btnRegister" id="btnRegister" tabindex="4" class="form-control btn btn-login" value="Register" onclick="sweetalertSpinner()">
</div>
</div>
</div>
</div>
}
</div>
正如 docs 所说:“模型状态表示来自两个子系统的错误:模型绑定和模型验证。”
ModelState
将仅表示一个模型,并且由于您正在定义视图模型
public class ViewModelVM
{
public LoginModel loginModel { get; set; }
public RegisterModel registerModel { get; set; }
}
然后模型绑定和模型验证将基于 ViewModelVM
的属性而不是它的对象中的属性,这就是为什么你会得到 ModelState.IsValid == true
我认为你可以使用的是每个模型的手动验证,here你可以找到一种方法。
或许您可以创建一个 class 并继承您想要的两个模型,但我不确定这是否可行。如果您尝试过,请告诉我们。
我找到了似乎是解决方案的方法。 将以下内容添加到 ViewModel
public class ViewModelVM
{
public LoginModel loginModel { get; set; }
public RegisterModel registerModel { get; set; }
public string txtUsername { get; set; }
public string txtPassword { get; set; }
public string txtFirstName { get; set; }
public string txtLastName { get; set; }
}
按如下方式更改每个表单域的视图(删除对 loginModel
和 registerModel
的引用):
@Html.ValidationMessageFor(x => x.txtUsername, "", new { @class = "text-danger labeltiny" })
像这样在控制器中将 LoginModel 作为参数而不是 ViewModelVM 传递(对 RegisterSubmit 执行相同操作):
[HttpPost]
public ActionResult LoginSubmit(LoginModel lm)
{
ViewModelVM vm = new ViewModelVM();
if (ModelState.IsValid)
{
//perform other logic using form fields lm.txtUsername, etc...
return View("Index");
}
else
{
return View("Login", vm);
}
}