JPG文件上传格式验证异常:无提示且流程无法正常执行
问题描述
需求:实现仅允许.jpg格式文件上传至本地存储,并将文件URL存入数据库;对每个上传文件进行格式校验,若存在非.jpg文件则终止流程并提示「Invalid file format」。
当前问题:代码执行时页面仅刷新,无错误提示,且正确格式文件也无法正常处理。
相关代码
Controller 代码
[HttpPost] [ValidateAntiForgeryToken] public IActionResult Upsert(DepartmentPageCreateVM departmentPageVM, List<IFormFile> files) { if (ModelState.IsValid) { if (departmentPageVM.DepartmentPage.DepartmentPageId == 0) { _context.DepartmentPages.Add(departmentPageVM.DepartmentPage); } else { _context.DepartmentPages.Update(departmentPageVM.DepartmentPage); } _context.SaveChanges(); string wwwRootPath = _webHostEnvironment.WebRootPath; if (files != null) { foreach (IFormFile file in files) { string fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName); string productPath = @"images/departments/department-" + departmentPageVM.DepartmentPage.DepartmentPageId; string finalPath = Path.Combine(wwwRootPath, productPath); if (!Directory.Exists(finalPath)) Directory.CreateDirectory(finalPath); // check file extension string extFile = Path.GetExtension(fileName); if (extFile != ".jpg") { ModelState.AddModelError("", "Invalid file format"); } using (var fileStream = new FileStream(Path.Combine(finalPath, fileName), FileMode.Create)) { file.CopyTo(fileStream); } DepartmentPhoto departmentPhoto = new() { DepartmentPhotoImageURL = @"/" + productPath + "/" + fileName, DepartmentPageId = departmentPageVM.DepartmentPage.DepartmentPageId, }; if (departmentPageVM.DepartmentPage.DepartmentPhoto == null) departmentPageVM.DepartmentPage.DepartmentPhoto = new List<DepartmentPhoto>(); departmentPageVM.DepartmentPage.DepartmentPhoto.Add(departmentPhoto); } _context.DepartmentPages.Update(departmentPageVM.DepartmentPage); _context.SaveChanges(); } return RedirectToAction("Index"); } else { departmentPageVM.DepartmentList = _context.Departments.ToList().Select(u => new SelectListItem { Text = u.DepartmentName, Value = u.DepartmentId.ToString() }); return View(departmentPageVM); } }
视图中的文件输入控件
<div class="form-group mt-4"> <label asp-for="DepartmentPage.DepartmentPhoto"></label> <input type="file" name="files" class="form-control" multiple /> </div>
ViewModel 代码
public class DepartmentPageCreateVM { public DepartmentPage DepartmentPage { get; set; } [ValidateNever] public IEnumerable<SelectListItem> DepartmentList { get; set; } }
DepartmentPhoto 模型
public class DepartmentPhoto { public int DepartmentPhotoId { get; set; } public string? DepartmentPhotoImageURL { get; set; } public int DepartmentPageId { get; set; } public DepartmentPage? DepartmentPage { get; set; } }
DepartmentPage 模型
public class DepartmentPage { public int DepartmentPageId { get; set; } public string Name { get; set; } public string ContentBody { get; set; } public int DepartmentId { get; set; } [ValidateNever] public Department Department { get; set; } [ValidateNever] public List<DepartmentPhoto> DepartmentPhoto { get; set; } }
问题原因及修复方案
核心问题点
- 校验逻辑无效且未终止流程:添加
ModelState错误后未中断执行,文件仍会被上传,且后续直接跳转Index页面,错误信息无法在视图中显示。 - 扩展名校验冗余且不严谨:重复从拼接后的文件名取扩展名,未统一大小写(如
.JPG会被误判)。 - 过早保存数据:文件校验未通过时,
DepartmentPage已被存入数据库,不符合“终止流程”的需求。 - 视图未展示错误:缺少错误提示控件,无法显示
ModelState中的错误信息。
修复后的Controller代码
[HttpPost] [ValidateAntiForgeryToken] public IActionResult Upsert(DepartmentPageCreateVM departmentPageVM, List<IFormFile> files) { // 先校验文件格式(如果有文件上传) if (files != null && files.Any()) { foreach (var file in files) { var ext = Path.GetExtension(file.FileName).ToLowerInvariant(); if (ext != ".jpg") { ModelState.AddModelError("", "Invalid file format"); break; // 终止校验,不再处理后续文件 } } } if (ModelState.IsValid) { bool isNew = departmentPageVM.DepartmentPage.DepartmentPageId == 0; if (isNew) { _context.DepartmentPages.Add(departmentPageVM.DepartmentPage); } else { _context.DepartmentPages.Update(departmentPageVM.DepartmentPage); } _context.SaveChanges(); string wwwRootPath = _webHostEnvironment.WebRootPath; if (files != null && files.Any()) { string productPath = @"images/departments/department-" + departmentPageVM.DepartmentPage.DepartmentPageId; string finalPath = Path.Combine(wwwRootPath, productPath); if (!Directory.Exists(finalPath)) Directory.CreateDirectory(finalPath); foreach (IFormFile file in files) { string fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName).ToLowerInvariant(); using (var fileStream = new FileStream(Path.Combine(finalPath, fileName), FileMode.Create)) { file.CopyTo(fileStream); } DepartmentPhoto departmentPhoto = new() { DepartmentPhotoImageURL = @"/" + productPath + "/" + fileName, DepartmentPageId = departmentPageVM.DepartmentPage.DepartmentPageId, }; if (departmentPageVM.DepartmentPage.DepartmentPhoto == null) departmentPageVM.DepartmentPage.DepartmentPhoto = new List<DepartmentPhoto>(); departmentPageVM.DepartmentPage.DepartmentPhoto.Add(departmentPhoto); } _context.DepartmentPages.Update(departmentPageVM.DepartmentPage); _context.SaveChanges(); } return RedirectToAction("Index"); } // ModelState无效时,重新加载下拉列表并返回视图 departmentPageVM.DepartmentList = _context.Departments.ToList().Select(u => new SelectListItem { Text = u.DepartmentName, Value = u.DepartmentId.ToString() }); return View(departmentPageVM); }
视图修改(添加错误提示)
在表单顶部添加错误展示控件:
<div asp-validation-summary="All" class="text-danger"></div>
额外优化建议
- 同时校验文件MIME类型,防止恶意修改扩展名绕过校验:
if (ext != ".jpg" || file.ContentType != "image/jpeg") { ModelState.AddModelError("", "Invalid file format"); break; } - 增加空文件校验,避免生成无效的文件记录。
内容的提问来源于stack exchange,提问作者user18776105
相关产品推荐
相关产品推荐

