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 ,创建项目时为不使用顶级语句
正文
- 创建参数验证注解
AllowedFileExtensionsAttribute.csusing Humanizer.Localisation; using System.ComponentModel.DataAnnotations; namespace NightMarketPlatformWeb.Validations { /// <summary> /// 自定义验证特性,用于验证文件扩展名是否在允许的列表中。 /// https://learn.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-9.0&source=recommendations#custom-attributes /// </summary> public class AllowedFileExtensionsAttribute : ValidationAttribute { private readonly string[] _allowedExtensions; public AllowedFileExtensionsAttribute(string[] allowedExtensions) { _allowedExtensions = allowedExtensions; } protected override ValidationResult? IsValid( object? value, ValidationContext validationContext) { var file = value as IFormFile; if (file != null) { var extension = Path.GetExtension(file.FileName).ToLower(); if (!_allowedExtensions.Contains(extension)) { // 获取属性的Display名称 var displayName = validationContext.DisplayName; // 替换错误消息中的{0}占位符 var errorMessage = string.Format(ErrorMessageString, displayName); // return new ValidationResult(errorMessage); } } return ValidationResult.Success; } } } - 创建接受参数的Dto,在文件属性上面添加上自定义注解
AllowedFileExtensions,并传入允许的格式[".png", ".jpg", ".jpeg", ".gif"](当前示例为:SettingEditRequestDto.cs)using NightMarketPlatformWeb.Validations; using System.ComponentModel.DataAnnotations; namespace NightMarketPlatformWeb.Dtos.Area { /// <summary> /// 请求DTO类 /// </summary> public class SettingEditRequestDto { [Display(Name = "系统名称")] [Required(ErrorMessage = "系统名称不能为空")] [StringLength(16, MinimumLength = 2, ErrorMessage = " {0} 区间为 {1} - {2}.")] public string SystemName { get; set; } = string.Empty; [Display(Name = "系统描述")] [Required(ErrorMessage = "系统描述不能为空")] [StringLength(120, MinimumLength = 2, ErrorMessage = " {0} 区间为 {1} - {2}.")] public string SystemDesc { get; set; } = string.Empty; // 留空则不修改 [Display(Name = "系统logo文件")] // 验证文件后缀 //[FileExtensionsAttribute(Extensions = "png,jpg,jpeg,gif", ErrorMessage = " {0} 格式错误")] // 验证文件后缀,自带 FileExtensionsAttribute 不满足 //[FileExtensionsAttribute(ErrorMessage = " {0} 格式错误")] [AllowedFileExtensions([".png", ".jpg", ".jpeg", ".gif"], ErrorMessage = " {0} 格式错误")] public IFormFile? SystemLogoFile { get; set; } // 留空则不修改 [Display(Name = "系统logo路径")] public string? SystemLogoPath { get; set; } } } - 视图文件
Index.cshtml@using NightMarketPlatformWeb.Dtos.Area @model SettingEditRequestDto @{ ViewData["Title"] = "设置"; } <h1>列表页</h1> <h4>设置</h4> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Index" enctype="multipart/form-data"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="SystemName" class="control-label"></label> <input asp-for="SystemName" class="form-control" /> <span asp-validation-for="SystemName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="SystemDesc" class="control-label"></label> <input asp-for="SystemDesc" class="form-control" /> <span asp-validation-for="SystemDesc" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="SystemLogoFile" class="control-label"></label> <input asp-for="SystemLogoFile" class="form-control" /> <span asp-validation-for="SystemLogoFile" class="text-danger"></span> <div> <img src="@Model.SystemLogoPath" class="img-rounded img-thumbnail mt-2 mb-2" width="150" height="150" /> </div> </div> <div class="form-group"> <input type="submit" value="保存" class="btn btn-primary" /> </div> </form> </div> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} } - 在控制器内验证、接收、移动文件
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using NightMarketPlatformWeb.Data; using NightMarketPlatformWeb.Dtos.Area; using NightMarketPlatformWeb.Models; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace NightMarketPlatformWeb.Controllers { // [Authorize(Roles = "Admin")] public class SettingController : Controller { private readonly ApplicationDbContext _context; public readonly IWebHostEnvironment _hostEnvironment; public SettingController(ApplicationDbContext context, IWebHostEnvironment hostEnvironment) { _context = context; _hostEnvironment = hostEnvironment; } // GET: Setting public async Task<IActionResult> Index() { // 获取所有设置记录 var settings = await _context.Settings.ToListAsync(); // 初始化DTO var dto = new SettingEditRequestDto(); // 遍历记录并映射到DTO对应的属性 foreach (var setting in settings) { switch (setting.SettingKey) { case "SystemName": dto.SystemName = setting.SettingValue; break; case "SystemDesc": dto.SystemDesc = setting.SettingValue; break; case "SystemLogoPath": dto.SystemLogoPath = setting.SettingValue; break; } } return View(dto); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Index(SettingEditRequestDto editRequestDto) { // 建议将验证放入筛选器中进行统一处理 if (!ModelState.IsValid) { return View(editRequestDto); } // 添加事务处理 using var transaction = await _context.Database.BeginTransactionAsync(); try { // 获取所有设置记录 var settings = await _context.Settings.ToListAsync(); // 系统名称 var systemNameRow = settings.Where(r => r.SettingKey == "SystemName").First(); systemNameRow.SettingValue = editRequestDto.SystemName; // 系统设置 var systemDescRow = settings.Where(r => r.SettingKey == "SystemDesc").First(); systemDescRow.SettingValue = editRequestDto.SystemDesc; // 系统logo 不修改则不更新 var systemLogoPathRow = settings.Where(r => r.SettingKey == "SystemLogoPath").First(); if (editRequestDto.SystemLogoFile != null) { // 文件操作逻辑 var newFileName = Path.GetRandomFileName(); var fileExt = Path.GetExtension(editRequestDto.SystemLogoFile.FileName); var uploadDir = Path.Combine("temps", DateTime.Now.ToString("yyyy_MM_dd")); var fileDir = Path.Combine(_hostEnvironment.WebRootPath, uploadDir); var filePath = Path.Combine(fileDir, newFileName + fileExt); // // 如果目录不存在则创建 if (!Directory.Exists(fileDir)) { Directory.CreateDirectory(fileDir); } // using var stream = System.IO.File.Create(filePath); await editRequestDto.SystemLogoFile.CopyToAsync(stream); systemLogoPathRow.SettingValue = Path.Combine(uploadDir, newFileName + fileExt); ; } // await _context.SaveChangesAsync(); // await transaction.CommitAsync(); } catch (Exception) { await transaction.RollbackAsync(); } return RedirectToAction(nameof(Index)); } } }
预览
- 界面预览

博 主 :夏秋初
地 址 :https://www.cnblogs.com/xiaqiuchu/p/19007697
如果对你有帮助,可以点一下 推荐 或者 关注 吗?会让我的分享变得更有动力~
转载时请带上原文链接,谢谢。
地 址 :https://www.cnblogs.com/xiaqiuchu/p/19007697
如果对你有帮助,可以点一下 推荐 或者 关注 吗?会让我的分享变得更有动力~
转载时请带上原文链接,谢谢。

浙公网安备 33010602011771号