ASP.NET Core MVC 使用过滤器实现表单自动验证
参考
- DeepSeek
- 豆包
- 其他(由于文章是后编写的,相关参考文章未存储连接)
环境
| 软件/系统 | 版本 | 说明 |
|---|---|---|
| Windows | windows 10 专业版 22H2 64 位操作系统, 基于 x64 的处理器 | |
| Microsoft Visual Studio | Community 2022 (64 位) - Current 版本 17.14.9 | |
| Visual Studio Code | 1.102.2 | |
| Docker Engine | v28.3.2 | Docker 桌面工具 |
| Docker | 28.3.2 | |
| pgAdmin4 | 9.0 | PostgreSQL 数据库管理软件 |
| PostgreSQL | 15 | |
| .NET | 8 | |
| ASP.NET Core MVC | ASP.NET Core MVC in .NET 8.0 | |
| Microsoft.EntityFrameworkCore.Design | 8.0.18 | nuget 依赖 |
| Microsoft.EntityFrameworkCore.Tools | 8.0.18 | nuget 依赖 |
| Microsoft.VisualStudio.Web.CodeGeneration.Design | 8.0.7 | nuget 依赖 (Microsoft Visual Studio在通过模型生成控制器与视图时自动安装的依赖) |
| Npgsql.EntityFrameworkCore.PostgreSQL | 8.0.11 | nuget 依赖 |
| EFCore.NamingConventions | 8.0.3 | nuget 依赖 |
| X.PagedList.EF | 10.5.7 | nuget 依赖 |
| X.PagedList.Mvc.Core | 10.5.7 | nuget 依赖(安装 X.PagedList.EF 时自动安装) |
本项目入口文件为 Program.cs ,创建项目时为不使用顶级语句
正文
- 编写筛选器
MultiFormatValidationFilter.csusing Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ViewFeatures; using NightMarketPlatformWeb.Controllers; namespace NightMarketPlatformWeb.Filters { /// <summary> /// 支持JSON和View的参数验证过滤器 /// </summary> public class MultiFormatValidationFilter : IAsyncActionFilter { private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory; private readonly IModelMetadataProvider _modelMetadataProvider; // 日志记录器 /// <summary> /// 构造函数注入依赖 /// </summary> public MultiFormatValidationFilter( ITempDataDictionaryFactory tempDataDictionaryFactory, IModelMetadataProvider modelMetadataProvider) { _tempDataDictionaryFactory = tempDataDictionaryFactory; _modelMetadataProvider = modelMetadataProvider; } /// <summary> /// 异步执行过滤器 /// </summary> public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 检查模型状态是否有效 if (!context.ModelState.IsValid) { // TODO : 此处根据请求的Accept头决定返回格式 await HandleViewResponse(context); return; } // 模型验证通过,继续执行 await next(); } /// <summary> /// 处理View响应 /// </summary> private Task HandleViewResponse(ActionExecutingContext context) { // 获取当前Action的信息 var actionDescriptor = context.ActionDescriptor; var controllerName = actionDescriptor.RouteValues["controller"]; var actionName = actionDescriptor.RouteValues["action"]; // 通常验证失败时返回提交表单的视图 // 可以根据需要修改为专用的错误视图 var viewName = actionName; // 获取提交的模型 var model = context.ActionArguments.Values.FirstOrDefault(); // 创建ViewResult var viewResult = new ViewResult { ViewName = viewName, // ViewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState) { Model = model }, TempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext) }; // 添加错误消息 //viewResult.ViewData["ValidationMessage"] = "表单验证失败,请检查输入并重新提交。"; context.Result = viewResult; return Task.CompletedTask; } } } - 在
Program.cs内注册筛选器// 注册控制器和视图 builder.Services.AddControllersWithViews(options => { // 注册全局验证过滤器 options.Filters.Add<MultiFormatValidationFilter>(); // 其他过滤器... }); - 接收请求的 Dto 字段上添加相关注解,此处使用
AdminEditRequestDto.cs举例。(相关注解可以参考微软文档)using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; namespace NightMarketPlatformWeb.Dtos.Area { /// <summary> /// 请求DTO类 /// </summary> public class AdminEditRequestDto { public int Id { get; set; } /// <summary> /// 管理员名称 /// </summary> [Required] // 显示名称 [Display(Name = "管理员名称")] public string AdminName { get; set; } = string.Empty; /// <summary> /// 管理员账号/管理员联系方式 /// </summary> [Required] // 显示名称 [Display(Name = "管理员账号/联系方式")] public string AdminPhoneNumber { get; set; } = string.Empty; /// <summary> /// 管理员密码(不填写则不修改,可为空,并且验证区间) /// </summary> // 显示名称 [Display(Name = "管理员密码")] [StringLength(16, MinimumLength = 8, ErrorMessage = " {0} 区间为 {1} - {2}.")] public string? AdminPassword { get; set; } // 显示名称 [Display(Name = "是否启用")] [Required(ErrorMessage = "{0}必填")] public bool Enabled { get; set; } = true; } } - 将添加相关验证注解的类作为传入参数,则会自动验证。(下面代码无需指定
if (!ModelState.IsValid)判断)using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NightMarketPlatformWeb.Data; using NightMarketPlatformWeb.Dtos.Admin; using NightMarketPlatformWeb.Dtos.Area; using NightMarketPlatformWeb.Models; using NightMarketPlatformWeb.Utils; using NightMarketPlatformWeb.ViewModels; using System.Security.Claims; using X.PagedList; using X.PagedList.EF; namespace NightMarketPlatformWeb.Controllers { // [Authorize(Roles = "Admin")] public class AdminController : Controller { private readonly ApplicationDbContext _context; public AdminController(ApplicationDbContext context) { _context = context; } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Edit(int id, AdminEditRequestDto requestDto) { var model = await _context.Admins.FirstAsync(m => m.Id == requestDto.Id); // mapper 转换映射 model.AdminName = requestDto.AdminName; model.AdminPhoneNumber = requestDto.AdminPhoneNumber; if (!string.IsNullOrEmpty(requestDto.AdminPassword)) { var hasher = new PasswordHasher<AdminModel>(); string hashedPassword = hasher.HashPassword(model, requestDto.AdminPassword); model.AdminPassword = hashedPassword; } model.Enabled = requestDto.Enabled; // 保存 await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } } } Edit.cshtml视图如下:@model NightMarketPlatformWeb.Models.AdminModel @{ ViewData["Title"] = "修改"; } <h1>修改</h1> <h4>管理员</h4> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Edit"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <input type="hidden" asp-for="Id" /> <div class="form-group"> <label asp-for="AdminName" class="control-label">@Html.DisplayNameFor(model => model.AdminName)</label> <input asp-for="AdminName" class="form-control" /> <span asp-validation-for="AdminName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="AdminPhoneNumber" class="control-label">@Html.DisplayNameFor(model => model.AdminPhoneNumber)</label> <input asp-for="AdminPhoneNumber" class="form-control" /> <span asp-validation-for="AdminPhoneNumber" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="AdminPassword" class="control-label">@Html.DisplayNameFor(model => model.AdminPassword)</label> <!--留空输入框 value="@string.Empty" 忽略验证 data-val="@string.Empty"--> <input asp-for="AdminPassword" class="form-control" value="@string.Empty" data-val="@string.Empty" /> <span asp-validation-for="AdminPassword" class="text-danger"></span> </div> <div class="form-group form-check"> <label class="form-check-label"> <input class="form-check-input" asp-for="Enabled" /> @Html.DisplayNameFor(model => model.Enabled) </label> </div> <div class="form-group"> <input type="submit" value="保存" class="btn btn-primary" /> </div> </form> </div> </div> <div> <a asp-action="Index">返回列表</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
博 主 :夏秋初
地 址 :https://www.cnblogs.com/xiaqiuchu/p/19007713
如果对你有帮助,可以点一下 推荐 或者 关注 吗?会让我的分享变得更有动力~
转载时请带上原文链接,谢谢。
地 址 :https://www.cnblogs.com/xiaqiuchu/p/19007713
如果对你有帮助,可以点一下 推荐 或者 关注 吗?会让我的分享变得更有动力~
转载时请带上原文链接,谢谢。

浙公网安备 33010602011771号