未验证 ASP.NET MVC5 模型

Posted

技术标签:

【中文标题】未验证 ASP.NET MVC5 模型【英文标题】:ASP.NET MVC5 model not being validated 【发布时间】:2021-09-07 12:21:54 【问题描述】:

我在我的模型上使用数据注释进行验证,但是当我测试应用程序时,模型被认为是有效的,即使表单完全是空的。这会导致异常,因为控制器中的注册方法引用了一个不存在的对象(因为如果表单无效,模型不应该被实例化)。

这是我的模特

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-\d4-\d4)|(\d-\d3-\d6)$", 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(@"^\d4-\d4$", 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");
            
        

不仅仅是错误信息没有打印在页面上,模型本身也被认为是有效的,即使每个字段都是必需的。

【问题讨论】:

【参考方案1】:

ModelState.IsValid 将始终为真,因为 FormCollection 对象没有针对它的验证规则。

您应该重构代码以接受 Client 对象而不是 FormCollection 作为 RegisterClient 方法的参数。这样 - MVC 将自动为您实例化对象并使用属性来验证它。

【讨论】:

谢谢!这似乎可行,但是 MVC 如何知道视图中的哪个字段对应于模型中的相应属性?控制器如何知道应该使用第一个输入字段的值来设置我的模型中的Id 属性? @Dasph MVC 使用输入 name="" 属性来匹配模型类中相同的属性。所以 将设置属性 FullName 的值。它也会尝试进行类型转换。

以上是关于未验证 ASP.NET MVC5 模型的主要内容,如果未能解决你的问题,请参考以下文章

客户端验证在带有 Bootstrap 的 ASP.NET MVC5 中不起作用

ASP.NET Web API 身份验证(Web + 移动)

表单身份验证、ASP.NET MVC 和 WCF RESTful 服务

在 Asp.Net Core 中使用 Swagger 在请求中未发送授权承载令牌

ASP.NET MVC5 自定义身份验证

将 ASP.NET MVC5 身份验证添加到现有项目