You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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; }
}

问题原因及修复方案

核心问题点

  1. 校验逻辑无效且未终止流程:添加ModelState错误后未中断执行,文件仍会被上传,且后续直接跳转Index页面,错误信息无法在视图中显示。
  2. 扩展名校验冗余且不严谨:重复从拼接后的文件名取扩展名,未统一大小写(如.JPG会被误判)。
  3. 过早保存数据:文件校验未通过时,DepartmentPage已被存入数据库,不符合“终止流程”的需求。
  4. 视图未展示错误:缺少错误提示控件,无法显示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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 00:50:09