.NET6 ASP.NET删除文件时触发ArgumentNullException问题排查
问题描述
我有一个TryGetByStatementId方法,通过FirstOrDefault方法从数据库中获取对应ID的数据。同时维护着一个存储上传文件信息的数据库,上传文件时,文件会保存到wwwroot目录,文件的ID、名称、创建时间等信息存入数据库。但调用TryGetByStatementId方法执行删除操作时,触发错误:System.ArgumentNullException: "Value cannot be null. Arg_ParamName_Name"
相关代码
文件上传控制器代码
public class ManagementController : Controller { private readonly ApplicationDbContext applicationDb; private readonly IWebHostEnvironment _webHostEnvironment; public ManagementController(ApplicationDbContext applicationDb, IWebHostEnvironment webHostEnvironment) { this.applicationDb = applicationDb; _webHostEnvironment = webHostEnvironment; } public IActionResult Index() { return View(); } [HttpPost] public async Task<IActionResult> AddFile(IFormFile uploadFile) { if (uploadFile != null) { string path = "/Files/" + uploadFile.FileName; using (var fileStream = new FileStream(_webHostEnvironment.WebRootPath + path, FileMode.Create)) { await uploadFile.CopyToAsync(fileStream); } StatementsDb file = new StatementsDb { StatementsName = uploadFile.FileName, CreateDateTime = DateTime.Now, Path = path}; applicationDb.statementsDbs.Add(file); applicationDb.SaveChanges(); } return RedirectToAction("Index"); } }
删除操作控制器代码片段
public IActionResult RemoveFile(int statementId) { statementsDb.Remove(statementId); return RedirectToAction("Index"); }
数据操作实体代码片段
public StatementsDb TryGetByStatementId(int id) { return applicationDb.statementsDbs.FirstOrDefault(statement => statement.StatementsId == id); } public void Remove(int statement) { var existingStatement = TryGetByStatementId(statement); applicationDb.statementsDbs.Remove(existingStatement); applicationDb.SaveChanges(); }
更新补充的Program代码
using archivingsystem.db; using archivingsystem.Helpers.AutoMapping; using AutoMapper; using Microsoft.EntityFrameworkCore; namespace archivingsystem { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); IMapper mapper = MappingConfig.RegisterMaps().CreateMapper(); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // AutoMapper builder.Services.AddSingleton(mapper); builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); // Services builder.Services.AddTransient<IStatementsDbRepository, StatementsDbRepository>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run(); } } }
错误原因
- 空值未处理:当
TryGetByStatementId传入的ID不存在时,FirstOrDefault返回null,直接调用Remove(null)会触发ArgumentNullException。 - 参数命名混淆:
Remove方法参数名statement实际接收的是ID值,命名歧义容易引发逻辑错误。 - 删除前未校验:执行删除操作前,没有检查获取到的
existingStatement是否为null,直接执行删除。
修复方案
1. 修改数据操作方法,增加空值校验
public StatementsDb TryGetByStatementId(int id) { return applicationDb.statementsDbs.FirstOrDefault(statement => statement.StatementsId == id); } public void Remove(int statementId) { var existingStatement = TryGetByStatementId(statementId); // 先校验对象是否存在 if (existingStatement != null) { applicationDb.statementsDbs.Remove(existingStatement); applicationDb.SaveChanges(); // 同步删除文件系统中的对应文件(可选但建议添加) var filePath = Path.Combine(_webHostEnvironment.WebRootPath, existingStatement.Path.TrimStart('/')); if (System.IO.File.Exists(filePath)) { System.IO.File.Delete(filePath); } } // 可根据需求添加对象不存在时的处理,比如记录日志或返回提示 }
2. 控制器中正确注入仓储服务
避免直接依赖上下文,改用注册的仓储接口:
public class ManagementController : Controller { private readonly IStatementsDbRepository _statementsRepo; private readonly IWebHostEnvironment _webHostEnvironment; public ManagementController(IStatementsDbRepository statementsRepo, IWebHostEnvironment webHostEnvironment) { _statementsRepo = statementsRepo; _webHostEnvironment = webHostEnvironment; } // ... 其他代码 public IActionResult RemoveFile(int statementId) { _statementsRepo.Remove(statementId); return RedirectToAction("Index"); } }
3. 可选:添加前端提示逻辑
在控制器中增加不存在时的提示,提升用户体验:
public IActionResult RemoveFile(int statementId) { var existingStatement = _statementsRepo.TryGetByStatementId(statementId); if (existingStatement == null) { TempData["ErrorMessage"] = "要删除的文件不存在"; return RedirectToAction("Index"); } _statementsRepo.Remove(statementId); TempData["SuccessMessage"] = "文件删除成功"; return RedirectToAction("Index"); }
内容的提问来源于stack exchange,提问作者Vivaldi
相关产品推荐
相关产品推荐

