当前位置: 首页 > news >正文

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 ,创建项目时为不使用顶级语句

正文

  1. 创建参数验证注解 AllowedFileExtensionsAttribute.cs
    using 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;}}
    }
  2. 创建接受参数的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; }}
    }
    
  3. 视图文件 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");}
    }
    
  4. 在控制器内验证、接收、移动文件
    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: Settingpublic async Task<IActionResult> Index(){// 获取所有设置记录var settings = await _context.Settings.ToListAsync();// 初始化DTOvar 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));}}
    }
    

预览

  • 界面预览
    image
http://www.wuyegushi.com/news/652.html

相关文章:

  • 政治学和行政学属于法学
  • 基于RK3399嵌入式Linux驱动开发课程
  • Java日志框架
  • ASP.NET Core MVC 使用 EF Core 实现字段自动填充(如:添加时间 CreatedTime、更新时间 UpdatedTime)
  • 山西大同旅游攻略
  • 7月27日总结
  • 线性回归算法
  • 什么?智能体生成智能体?自我进化? - 戴维
  • 使用 Claude Code 的自定义 Sub Agent 完善博文写作体验
  • MCP 如何将你的 AI 从聊天机器人转变为工作流自动化利器
  • uart回环验证
  • POLIR-Laws-民法典:委托合同、行纪合同 和 中介合同 等的区别
  • MongoDB 安全数据替换脚本 (执行顺序:备份→校验→确认→清空→还原指定数据→失败回滚到备份)
  • 望言OCR视频字幕提取2025终极评测:免费版VS专业版提全方位对比(含免费下载
  • ASP.NET Core MVC 使用 X.PagedList.EF 实现分页、条件查询
  • 探索C++世界的奥秘:从核心特性到高效开发实践
  • 我的开源项目-PandaCoder迎来史诗级大更新啦
  • mongoDB 数据库的备份导出
  • 我在Android应用中发现硬编码的Facebook和Google API密钥(以及为什么这是个坏主意)
  • img convert
  • PPT_1 Word 内容 转 PPT
  • ACCESS 导出附件
  • 第二周假期进度报告(7.20 - 7.26)
  • CVE-2020-11981 Apache Airflow Celery 消息中间件命令执行漏洞 (复现)
  • nlogn分解质因数 - SPF(目前以学习最快分解质因数)
  • 在express中使用sqlite数据库的方法
  • 7.27
  • [ROI 2023] 峰值 (Day 1)
  • ASP.NET Core MVC 使用 EF Core 实现实体属性驼峰转下划线
  • C++运算符重载