ASP.NET MVC5 模型未经过验证
ASP.NET MVC5 model not being validated
我在我的模型上使用数据注释进行验证,但是当我测试应用程序时,该模型被认为是有效的,即使表单完全是空的。这会导致异常,因为控制器中的注册方法引用了一个不存在的对象(因为如果表单无效,则不应实例化模型)。
这是我的模型
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace MVCExample.Models
{
public class Client
{
[Required(ErrorMessage="ID Cannot be empty.")]
[RegularExpression(@"^(0\d-\d{4}-\d{4})|(\d-\d{3}-\d{6})$", ErrorMessage ="ID Format is Invalid.")]
[StringLength(12, ErrorMessage="Length cannot be greater than 12.", MinimumLength = 12)]
public string Id { get; set; }
[Required(ErrorMessage = "Name cannot be empty.")]
[StringLength(60, ErrorMessage = "Name must be between 10 and 60 characters.", MinimumLength = 10)]
public string FullName { get; set; }
[Required(ErrorMessage = "Phone number cannot be empty.")]
[StringLength(9, ErrorMessage = "Phone number must have 9 characters.", MinimumLength = 9)]
[RegularExpression(@"^\d{4}-\d{4}$", ErrorMessage ="Phone Format is incorrect.")]
public string PhoneNumber { get; set; }
[Required(ErrorMessage = "Must choose a discount option.")]
public bool Discount { get; set; }
[Required(ErrorMessage = "Invalid Amount.")]
[RegularExpression(@"^\d+$", ErrorMessage ="Value must be a number.")]
[Range(1, double.MaxValue, ErrorMessage ="Amount must be greater than 0.")]
public decimal RecentPurchasesAmount { get; set; }
[Required(ErrorMessage = "Invalid Amount.")]
[RegularExpression(@"^\d+$", ErrorMessage = "Value must be a number.")]
[Range(1, double.MaxValue, ErrorMessage ="Amount must be greater than 0.")]
public decimal LastYearPurchases { get; set; }
[Required(ErrorMessage = "Invalid Amount.")]
[RegularExpression(@"^\d+$", ErrorMessage = "Value must be a number.")]
[Range(1, int.MaxValue, ErrorMessage ="Amount must be greater than 0.")]
public int AcUnitsPurchased { get; set; }
public Client() { }
public Client(string pId, string pName, string pPhone, bool pDisc, decimal pRecentPurchase, decimal pLastYearPurchase, int pUnits)
{
this.Id = pId;
this.FullName = pName;
this.PhoneNumber = pPhone;
this.Discount = pDisc;
this.RecentPurchasesAmount = pRecentPurchase;
this.LastYearPurchases = pLastYearPurchase;
this.AcUnitsPurchased = pUnits;
}
}
}
cshtml 视图
@model MVCExample.Models.Client
@{
ViewBag.Title = "Example";
ViewBag.Message = "Registration";
}
<h1 class="store-title">@ViewBag.Title</h1>
<h2 class="page-title">@ViewBag.Message</h2>
@using (Html.BeginForm("RegisterClient", "AppRegistration"))
{
@Html.AntiForgeryToken();
<label for="inp_registryId">Id</label>
<input type="text" id="inp_registryId" name="Id" />
//This is never showing up in the browser.
@Html.ValidationMessageFor(model => model.Id, null, new { @class="text-danger"})
<label for="inp_registryFullName">Full Name</label>
<input type="text" id="inp_registryFullName" name="FullName" />
<label for="inp_registryTelephone">Phone</label>
<input type="text" id="inp_registryTelephone" name="Phone" />
<div class="radio-box">
<p>Client qualifies for discount</p>
<label for="radioBtn_registryDiscountYes">Yes</label>
<input type="radio" id="radioBtn_registryDiscountYes" value="true" name="radioBtnDiscount" />
<label for="radioBtn_registryDiscountNo">No</label>
<input type="radio" id="radioBtn_registryDiscountNo" value="false" name="radioBtnDiscount" />
</div>
<label for="inp_registryRecentPurchases">Amount for recent purchases</label>
<input type="number" id="inp_registryRecentPurchases" name="RecentPurchases"/>
<label for="inp_registryLastYearPurchases">Amount for last year purchases</label>
<input type="number" id="inp_registryLastYearPurchases" name="LastYearPurchases" />
<label for="inp_registryAcUnitsPurchased">Units purchased</label>
<input type="number" id="inp_registryAcUnitsPurchased" name="UnitsPurchased" />
<button type="submit" id="btnRegister">Register</button>
}
正在调用控制器方法
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RegisterClient(FormCollection collection)
{
try {
//This code is executing even if the form is empty.
if (ModelState.IsValid) {
ViewData["Id"] = collection["Id"];
ViewData["FullName"] = collection["FullName"];
ViewData["Phone"] = collection["Phone"];
ViewData["Discount"] = collection["radioBtnDiscount"];
ViewData["RecentPurchases"] = collection["RecentPurchases"];
ViewData["LastYearPurchases"] = collection["LastYearPurchases"];
ViewData["UnitsPurchased"] = collection["UnitsPurchased"];
string id = ViewData["Id"].ToString();
string fullName = ViewData["FullName"].ToString();
string phone = ViewData["Phone"].ToString();
/*Exceptions happen from this point, since it's trying to reference null values */
bool discount = Boolean.Parse(ViewData["Discount"].ToString());
decimal recentPurchases = Decimal.Parse(ViewData["RecentPurchases"].ToString());
decimal lastYearPurchases = Decimal.Parse(ViewData["LastYearPurchases"].ToString());
int unitsPurchased = Int32.Parse(ViewData["UnitsPurchased"].ToString());
registeredClients.Add(new Client(id, fullName, phone, discount, recentPurchases, lastYearPurchases, unitsPurchased));
return View("Registration");
} else
{
Debug.WriteLine("Not registered.");
return View();
}
} catch(Exception ex)
{
Debug.WriteLine(ex.StackTrace);
return View("Registration");
}
}
不仅错误消息没有打印在页面上,模型本身也被认为是有效的,即使每个字段都是必需的。
ModelState.IsValid 将始终为真,因为 FormCollection 对象没有针对它的验证规则。
您应该重构代码以接受 Client 对象而不是 FormCollection 作为 RegisterClient 方法的参数。这样 - MVC 将自动为您实例化对象并使用属性来验证它。
我在我的模型上使用数据注释进行验证,但是当我测试应用程序时,该模型被认为是有效的,即使表单完全是空的。这会导致异常,因为控制器中的注册方法引用了一个不存在的对象(因为如果表单无效,则不应实例化模型)。
这是我的模型
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace MVCExample.Models
{
public class Client
{
[Required(ErrorMessage="ID Cannot be empty.")]
[RegularExpression(@"^(0\d-\d{4}-\d{4})|(\d-\d{3}-\d{6})$", ErrorMessage ="ID Format is Invalid.")]
[StringLength(12, ErrorMessage="Length cannot be greater than 12.", MinimumLength = 12)]
public string Id { get; set; }
[Required(ErrorMessage = "Name cannot be empty.")]
[StringLength(60, ErrorMessage = "Name must be between 10 and 60 characters.", MinimumLength = 10)]
public string FullName { get; set; }
[Required(ErrorMessage = "Phone number cannot be empty.")]
[StringLength(9, ErrorMessage = "Phone number must have 9 characters.", MinimumLength = 9)]
[RegularExpression(@"^\d{4}-\d{4}$", ErrorMessage ="Phone Format is incorrect.")]
public string PhoneNumber { get; set; }
[Required(ErrorMessage = "Must choose a discount option.")]
public bool Discount { get; set; }
[Required(ErrorMessage = "Invalid Amount.")]
[RegularExpression(@"^\d+$", ErrorMessage ="Value must be a number.")]
[Range(1, double.MaxValue, ErrorMessage ="Amount must be greater than 0.")]
public decimal RecentPurchasesAmount { get; set; }
[Required(ErrorMessage = "Invalid Amount.")]
[RegularExpression(@"^\d+$", ErrorMessage = "Value must be a number.")]
[Range(1, double.MaxValue, ErrorMessage ="Amount must be greater than 0.")]
public decimal LastYearPurchases { get; set; }
[Required(ErrorMessage = "Invalid Amount.")]
[RegularExpression(@"^\d+$", ErrorMessage = "Value must be a number.")]
[Range(1, int.MaxValue, ErrorMessage ="Amount must be greater than 0.")]
public int AcUnitsPurchased { get; set; }
public Client() { }
public Client(string pId, string pName, string pPhone, bool pDisc, decimal pRecentPurchase, decimal pLastYearPurchase, int pUnits)
{
this.Id = pId;
this.FullName = pName;
this.PhoneNumber = pPhone;
this.Discount = pDisc;
this.RecentPurchasesAmount = pRecentPurchase;
this.LastYearPurchases = pLastYearPurchase;
this.AcUnitsPurchased = pUnits;
}
}
}
cshtml 视图
@model MVCExample.Models.Client
@{
ViewBag.Title = "Example";
ViewBag.Message = "Registration";
}
<h1 class="store-title">@ViewBag.Title</h1>
<h2 class="page-title">@ViewBag.Message</h2>
@using (Html.BeginForm("RegisterClient", "AppRegistration"))
{
@Html.AntiForgeryToken();
<label for="inp_registryId">Id</label>
<input type="text" id="inp_registryId" name="Id" />
//This is never showing up in the browser.
@Html.ValidationMessageFor(model => model.Id, null, new { @class="text-danger"})
<label for="inp_registryFullName">Full Name</label>
<input type="text" id="inp_registryFullName" name="FullName" />
<label for="inp_registryTelephone">Phone</label>
<input type="text" id="inp_registryTelephone" name="Phone" />
<div class="radio-box">
<p>Client qualifies for discount</p>
<label for="radioBtn_registryDiscountYes">Yes</label>
<input type="radio" id="radioBtn_registryDiscountYes" value="true" name="radioBtnDiscount" />
<label for="radioBtn_registryDiscountNo">No</label>
<input type="radio" id="radioBtn_registryDiscountNo" value="false" name="radioBtnDiscount" />
</div>
<label for="inp_registryRecentPurchases">Amount for recent purchases</label>
<input type="number" id="inp_registryRecentPurchases" name="RecentPurchases"/>
<label for="inp_registryLastYearPurchases">Amount for last year purchases</label>
<input type="number" id="inp_registryLastYearPurchases" name="LastYearPurchases" />
<label for="inp_registryAcUnitsPurchased">Units purchased</label>
<input type="number" id="inp_registryAcUnitsPurchased" name="UnitsPurchased" />
<button type="submit" id="btnRegister">Register</button>
}
正在调用控制器方法
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RegisterClient(FormCollection collection)
{
try {
//This code is executing even if the form is empty.
if (ModelState.IsValid) {
ViewData["Id"] = collection["Id"];
ViewData["FullName"] = collection["FullName"];
ViewData["Phone"] = collection["Phone"];
ViewData["Discount"] = collection["radioBtnDiscount"];
ViewData["RecentPurchases"] = collection["RecentPurchases"];
ViewData["LastYearPurchases"] = collection["LastYearPurchases"];
ViewData["UnitsPurchased"] = collection["UnitsPurchased"];
string id = ViewData["Id"].ToString();
string fullName = ViewData["FullName"].ToString();
string phone = ViewData["Phone"].ToString();
/*Exceptions happen from this point, since it's trying to reference null values */
bool discount = Boolean.Parse(ViewData["Discount"].ToString());
decimal recentPurchases = Decimal.Parse(ViewData["RecentPurchases"].ToString());
decimal lastYearPurchases = Decimal.Parse(ViewData["LastYearPurchases"].ToString());
int unitsPurchased = Int32.Parse(ViewData["UnitsPurchased"].ToString());
registeredClients.Add(new Client(id, fullName, phone, discount, recentPurchases, lastYearPurchases, unitsPurchased));
return View("Registration");
} else
{
Debug.WriteLine("Not registered.");
return View();
}
} catch(Exception ex)
{
Debug.WriteLine(ex.StackTrace);
return View("Registration");
}
}
不仅错误消息没有打印在页面上,模型本身也被认为是有效的,即使每个字段都是必需的。
ModelState.IsValid 将始终为真,因为 FormCollection 对象没有针对它的验证规则。
您应该重构代码以接受 Client 对象而不是 FormCollection 作为 RegisterClient 方法的参数。这样 - MVC 将自动为您实例化对象并使用属性来验证它。