遍历ModelState中存储的错误信息

本文介绍了一种在服务器端进行表单验证的方法,并详细解释了如何从ModelState中获取并展示验证错误信息,以减少重复代码,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在服务器端验证中,有时我们添加了一个ModelError,然后还需要将该信息以JS的形式返回到客户端。如:

复制代码
[HttpPost]
        public ActionResult Index(LogOnModel model)
        {
            if (string.IsNullOrEmpty(model.UserName))
            {
                ModelState.AddModelError("UserName", "请输入用户名。");
                return JavaScript("alert('请输入用户名')");
            }
            if (string.IsNullOrEmpty(model.PassWord))
            {
                ModelState.AddModelError("UserName", "请输入密码。");
                return JavaScript("alert('请输入密码')");
            }
            if (string.IsNullOrEmpty(model.CheckCode))
            {
                ModelState.AddModelError("UserName", "请输入验证码。");
                return JavaScript("alert('请输入验证码')");
            }
            if (ModelState.IsValid)
            {
                Response.Write("asdf");
            }
            return View();
        }
复制代码

这样重写一遍固然可以,但却做了重复的工作,如果我们能获取添加在ModelState中的错误信息,则可以省去不少的工作。

ModelState本身是一个字典,并且存储了验证失败的信息。具体被存储在ModelState.Values[i].Errors[j].ErrorMessage属性中。

ModelState的Errors属性存储了所有验证失败信息,是一个ModelErrorCollection类型,ModelErrorCollection是一个ModelError的集合,而ModelError的ErrorMessage属性包含了验证失败错误信息。

大致是这样: 

○ ModelStateDictionary实际上是IDictionary<string, ModelState>类型
○ ModelState.Errors属性实际上是ModelErrorCollection类型
○ ModelErrorCollection实际上是ICollection<ModelError>类型
○ ModelError.ErrorMessage属性存储着所有验证失败信息

接下来的工作,其实就是如何把这个验证信息找出来。我们先手工添加一条验证信息,然后试图显示它:

ModelState.AddModelError("UserName", "请输入用户名。");
return JavaScript("alert('" + ModelState.Values.First().Errors[0].ErrorMessage + "')");

上面的代码中,Values集合表示的为不同的键值,而Errors则表示同一键值下的不同信息。

复制代码
ModelState.AddModelError("UserName", "请输入用户名。");
ModelState.AddModelError("UserName", "用户名不正确。");
ModelState.AddModelError("PassWord", "请输入密码。");
ModelState.AddModelError("PassWord", "密码不正确。");
//输出第一条
return Content(ModelState.Values.First().Errors[0].ErrorMessage);
//输出第二条
return Content(ModelState.Values.First().Errors[1].ErrorMessage);
//输出第三条
return Content(ModelState.Values.Skip(1).First().Errors[0].ErrorMessage);
//输出第四条
return Content(ModelState.Values.Skip(1).First().Errors[1].ErrorMessage);
复制代码

清楚了这些,遍历一个ModelState也就不难了。

复制代码
                StringBuilder errinfo = new StringBuilder();
                foreach (var s in ModelState.Values)
                {
                    foreach (var p in s.Errors)
                    {
                        errinfo.AppendFormat("{0}\\n", p.ErrorMessage);
                    }
                }

                return JavaScript("alert('" + errinfo.ToString() + "')");
复制代码

以下分别是集中显示错误信息和依次显示错误信息的代码:

集中显示错误信息:

复制代码
[HttpPost]
        public ActionResult Index(LogOnModel model)
        {
            if (string.IsNullOrEmpty(model.UserName))
            {
                ModelState.AddModelError("UserName", "请输入用户名。");
            }
            if (string.IsNullOrEmpty(model.PassWord))
            {
                ModelState.AddModelError("PassWord", "请输入密码。");
            }
            if (string.IsNullOrEmpty(model.CheckCode))
            {
                ModelState.AddModelError("ChkCode", "请输入验证码。");
            }
            if (!ModelState.IsValid)
            {
                StringBuilder errinfo = new StringBuilder();
                foreach (var s in ModelState.Values)
                {
                    foreach (var p in s.Errors)
                    {
                        errinfo.AppendFormat("{0}\\n", p.ErrorMessage);
                    }
                }
                return JavaScript("alert('" + errinfo.ToString() + "')");
            }
            return View();
        }
复制代码

依次逐条显示错误信息:

复制代码
[HttpPost]
        public ActionResult Index(LogOnModel model)
        {
            if (string.IsNullOrEmpty(model.UserName))
            {
                ModelState.AddModelError("UserName", "请输入用户名。");
                return JavaScript("alert('" + ModelState.Values.First().Errors[0].ErrorMessage + "')");
            }
            if (string.IsNullOrEmpty(model.PassWord))
            {
                ModelState.AddModelError("UserName", "请输入密码。");
                return JavaScript("alert('" + ModelState.Values.First().Errors[0].ErrorMessage + "')");
            }
            if (string.IsNullOrEmpty(model.CheckCode))
            {
                ModelState.AddModelError("UserName", "请输入验证码。");
                return JavaScript("alert('" + ModelState.Values.First().Errors[0].ErrorMessage + "')");
            }
            if (ModelState.IsValid)
            {
                
            }
            return View();
        }
复制代码
<think>我们讨论的是在 Ant Design Vue 中使用表单验证,特别是 `validateField` 方法。 在 Ant Design Vue 中,我们使用 `a-form-model` 组件来创建表单,并通过 `a-form-model-item` 来包裹表单项。 每个表单项可以设置 `prop` 属性,用于关联验证规则。规则在 `a-form-model` 的 `rules` 属性中定义。 有时我们不需要验证整个表单,而只需要验证单个字段,这时可以使用 `validateField` 方法。 以下是一个示例,展示如何在 Ant Design Vue 中使用 `validateField` 来验证单个字段。 步骤: 1. 使用 `a-form-model` 创建表单,并绑定 `model` 和 `rules`。 2. 在表单项中设置 `prop` 属性,使其与 `rules` 中的规则对应。 3. 通过 `ref` 获取表单实例,然后调用 `validateField` 方法。 示例代码: ```vue <template> <div> <a-form-model ref="ruleForm" :model="form" :rules="rules" > <a-form-model-item label="用户名" prop="username"> <a-input v-model="form.username" /> </a-form-model-item> <a-form-model-item label="邮箱" prop="email"> <a-input v-model="form.email" /> </a-form-model-item> <a-form-model-item> <a-button type="primary" @click="validateUsername">验证用户名</a-button> <a-button @click="resetField('username')">重置用户名</a-button> </a-form-model-item> </a-form-model> </div> </template> <script> export default { data() { return { form: { username: '', email: '', }, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 3, max: 5, message: '长度在3到5个字符', trigger: 'blur' } ], email: [ { required: true, message: '请输入邮箱', trigger: 'blur' }, { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' } ] } }; }, methods: { validateUsername() { // 验证单个字段:username this.$refs.ruleForm.validateField('username', (valid, message) => { if (!valid) { console.log('验证失败:', message); this.$message.error(message); } else { console.log('验证成功'); this.$message.success('用户名验证通过'); } }); }, resetField(fieldName) { // 重置单个字段的验证状态和值(重置为初始值) this.$refs.ruleForm.resetFields([fieldName]); } } }; </script> ``` ### 代码解释: 1. **表单结构**: - 使用 `a-form-model` 包裹整个表单,通过 `ref` 注册引用以便在方法中访问表单实例。 - 每个 `a-form-model-item` 的 `prop` 属性对应 `rules` 中的规则键名。 2. **验证规则**: - `rules` 是一个对象,键为字段名(如 `username`、`email`),值为规则数组。 - 每条规则可以设置 `required`(必填)、`min`/`max`(长度)、`type`(类型)等,以及自定义验证函数。 3. **validateField 方法**: - 通过 `this.$refs.ruleForm.validateField` 调用,第一个参数是字段名(字符串或数组),第二个参数是回调函数。 - 回调函数参数:`(valid, message)`,其中 `valid` 表示是否验证通过,`message` 是错误信息(当验证失败时)或空(验证通过时)。 4. **重置字段**: - 使用 `resetFields` 方法可以重置整个表单或指定字段(传入字段名的数组)的验证状态和值(重置为初始值)。 ### 注意事项: - `validateField` 可以接受一个字段名的数组,同时验证多个字段。 - 如果不传递回调函数,`validateField` 会返回一个 Promise(在 Ant Design Vue 2.x 中支持,具体版本请查看文档)。 - 在 Ant Design Vue 1.x 和 2.x 中,表单组件的使用方式可能略有不同,请根据实际版本调整。 §§相关问题§§: 1. 如何在 Ant Design Vue 中自定义表单验证规则? 2. 如何实现表单提交时的整体验证? 3. 在 Ant Design Vue 中,如何清除单个字段的验证状态(不重置值)? 4. 如何使用异步验证规则(例如验证用户名是否已存在)?</think># Ant Design Vue 表单字段验证指南 在 Ant Design Vue 中,`validateField` 方法用于对单个表单字段进行验证,而不是整个表单。这在需要实时验证特定字段或根据用户输入动态验证的场景中非常有用。 以下是一个完整的 Ant Design Vue 表单字段验证示例: ```vue <template> <div class="form-container"> <a-form-model ref="formRef" :model="form" :rules="rules" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }" > <h2>用户注册表单</h2> <a-form-model-item label="用户名" prop="username"> <a-input v-model="form.username" placeholder="请输入用户名" @blur="validateField('username')" /> <p v-if="errors.username" class="error-text">{{ errors.username }}</p> </a-form-model-item> <a-form-model-item label="邮箱" prop="email"> <a-input v-model="form.email" placeholder="请输入邮箱" @blur="validateField('email')" @input="validateField('email')" /> <p v-if="errors.email" class="error-text">{{ errors.email }}</p> </a-form-model-item> <a-form-model-item label="密码" prop="password"> <a-input-password v-model="form.password" placeholder="请输入密码" @blur="validateField('password')" /> <p v-if="errors.password" class="error-text">{{ errors.password }}</p> </a-form-model-item> <a-form-model-item label="确认密码" prop="confirmPassword"> <a-input-password v-model="form.confirmPassword" placeholder="请再次输入密码" @blur="validateField('confirmPassword')" /> <p v-if="errors.confirmPassword" class="error-text">{{ errors.confirmPassword }}</p> </a-form-model-item> <a-form-model-item :wrapper-col="{ span: 14, offset: 6 }"> <a-button type="primary" @click="validateForm">提交表单</a-button> <a-button style="margin-left: 10px" @click="resetForm">重置</a-button> <a-button style="margin-left: 10px" @click="validateAllFields">验证所有字段</a-button> </a-form-model-item> </a-form-model> <div class="form-state"> <h3>表单状态</h3> <pre>{{ formState }}</pre> </div> </div> </template> <script> export default { data() { // 自定义确认密码验证规则 const validateConfirmPassword = (rule, value, callback) => { if (value !== this.form.password) { callback(new Error('两次输入的密码不一致')); } else { callback(); } }; return { form: { username: '', email: '', password: '', confirmPassword: '' }, errors: { username: '', email: '', password: '', confirmPassword: '' }, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 3, max: 16, message: '用户名长度在3到16个字符', trigger: 'blur' } ], email: [ { required: true, message: '请输入邮箱地址', trigger: 'blur' }, { type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' }, { min: 6, max: 20, message: '密码长度在6到20个字符', trigger: 'blur' }, { pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/, message: '密码必须包含大小写字母和数字', trigger: 'blur' } ], confirmPassword: [ { required: true, message: '请确认密码', trigger: 'blur' }, { validator: validateConfirmPassword, trigger: 'blur' } ] } }; }, computed: { formState() { return { formData: { ...this.form }, errors: { ...this.errors }, isValid: Object.values(this.errors).every(error => error === '') }; } }, methods: { // 验证单个字段 validateField(fieldName) { this.$refs.formRef.validateField(fieldName, (errorMessage) => { if (errorMessage) { this.errors[fieldName] = errorMessage; } else { this.errors[fieldName] = ''; } // 特殊处理:当密码或确认密码变化时验证两者 if (fieldName === 'password' && this.form.confirmPassword) { this.validateField('confirmPassword'); } else if (fieldName === 'confirmPassword' && this.form.password) { this.validateField('password'); } }); }, // 验证所有字段 validateAllFields() { Object.keys(this.form).forEach(field => { this.validateField(field); }); }, // 验证整个表单 validateForm() { this.$refs.formRef.validate(valid => { if (valid) { this.$message.success('表单验证通过!'); // 这里可以提交表单数据 console.log('提交的表单数据:', this.form); } else { this.$message.error('表单验证失败,请检查输入'); this.validateAllFields(); // 显示所有错误 } }); }, // 重置表单 resetForm() { this.$refs.formRef.resetFields(); Object.keys(this.errors).forEach(key => { this.errors[key] = ''; }); this.$message.info('表单已重置'); } } }; </script> <style scoped> .form-container { max-width: 600px; margin: 20px auto; padding: 20px; border: 1px solid #e8e8e8; border-radius: 4px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); } h2 { text-align: center; margin-bottom: 24px; color: #1890ff; } .error-text { color: #f5222d; margin-top: 4px; margin-bottom: 0; } .form-state { margin-top: 30px; padding: 15px; background-color: #fafafa; border: 1px solid #e8e8e8; border-radius: 4px; } .form-state h3 { margin-top: 0; color: #595959; } pre { background-color: #fff; padding: 10px; border-radius: 4px; overflow: auto; } </style> ``` ## 代码解释 ### 1. 表单结构 - 使用 `<a-form-model>` 组件创建表单容器 - 每个表单项使用 `<a-form-model-item>` 包裹 - `prop` 属性将表单项与验证规则关联 - `@blur` 和 `@input` 事件触发字段验证 ### 2. 验证规则 - 在 `rules` 对象中定义每个字段的验证规则 - 支持多种验证类型:必填、长度限制、正则表达式、自定义验证函数 - 自定义验证函数示例:`validateConfirmPassword` 用于确认密码验证 ### 3. validateField 方法 ```javascript validateField(fieldName) { this.$refs.formRef.validateField(fieldName, (errorMessage) => { if (errorMessage) { this.errors[fieldName] = errorMessage; } else { this.errors[fieldName] = ''; } // 特殊处理密码字段的联动验证 if (fieldName === 'password' && this.form.confirmPassword) { this.validateField('confirmPassword'); } else if (fieldName === 'confirmPassword' && this.form.password) { this.validateField('password'); } }); } ``` - 通过 `$refs.formRef.validateField` 调用验证方法 - 第一个参数是要验证的字段名 - 第二个参数是回调函数,接收验证结果 - 验证结果存储在 `errors` 对象中用于显示错误信息 ### 4. 其他方法 - **validateAllFields()**: 遍历所有字段并验证 - **validateForm()**: 验证整个表单 - **resetForm()**: 重置表单字段和错误状态 ### 5. 表单状态 - 使用计算属性 `formState` 实时显示表单数据和验证状态 - 错误信息存储在 `errors` 对象中 ## 最佳实践 1. **触发时机**: - 使用 `@blur` 在用户离开字段时验证 - 使用 `@input` 实现实时验证(如邮箱格式验证) - 避免在每次输入时验证所有字段,影响性能 2. **错误显示**: - 使用单独的错误信息对象存储错误消息 - 在表单项下方显示错误信息 - 使用明显的视觉样式(红色文字)表示错误 3. **联动验证**: - 当密码字段变化时,自动验证确认密码字段 - 当确认密码字段变化时,自动验证密码字段 4. **表单状态管理**: - 提供清晰的表单状态展示 - 在提交前验证所有字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值