ASP.NET Core 6 Web API中IFormFile参数引发NotSupportedException问题
问题原因分析
异常的核心原因是:Dapper不识别EF Core的[NotMapped]特性。虽然你在模型的imageFile属性上加了[NotMapped],但这个特性仅对EF Core生效,Dapper会遍历对象的所有公共属性尝试转换为SQL参数。而IFormFile是ASP.NET Core用于处理文件上传的类型,无法被转换为数据库可接受的参数类型,因此抛出System.NotSupportedException。
另外,你在SaveInstitute方法中创建的values对象虽然复制了部分属性,但它本质还是InstituteInfo类型,仍然包含imageFile属性(即使未赋值,属性本身依然存在),Dapper依然会尝试处理这个属性。
解决方法
方法1:使用匿名类型传递参数(最简单直接)
直接在Dapper的Execute方法中使用匿名类型,只传入存储过程需要的参数,完全避开imageFile属性:
public int SaveInstitute(InstituteInfo info, string connectionID = "Default") { // 仅传递存储过程需要的参数,排除imageFile var parameters = new { info.ID, info.Institute_Name, info.Office_No, info.Cell_No, info.email, info.Institute_address, info.monogramPath }; using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionID)); return connection.Execute("sp_SaveNewInstitute", parameters, commandType: CommandType.StoredProcedure); }
方法2:创建数据库操作专用DTO
定义一个仅包含数据库字段的DTO类,避免业务模型和数据库模型耦合:
// 数据库操作专用DTO public class InstituteInfoDbDto { public int? ID { get; set; } = 1; public string Institute_Name { get; set; } = ""; public string Office_No { get; set; } = ""; public string Cell_No { get; set; } = ""; public string email { get; set; } = ""; public string Institute_address { get; set; } = ""; public string monogramPath { get; set; } = ""; }
修改数据访问方法:
public int SaveInstitute(InstituteInfoDbDto infoDto, string connectionID = "Default") { using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionID)); return connection.Execute("sp_SaveNewInstitute", infoDto, commandType: CommandType.StoredProcedure); }
控制器中转换模型:
// 在Post方法中调用前转换 var dbDto = new InstituteInfoDbDto { ID = Newinfo.ID, Institute_Name = Newinfo.Institute_Name, Office_No = Newinfo.Office_No, Cell_No = Newinfo.Cell_No, email = Newinfo.email, Institute_address = Newinfo.Institute_address, monogramPath = Newinfo.monogramPath }; var result = _sqlDataAccess.SaveInstitute(dbDto);
方法3:手动构建DynamicParameters(最灵活)
使用Dapper的DynamicParameters类,逐个添加需要的参数,精确控制参数列表:
public int SaveInstitute(InstituteInfo info, string connectionID = "Default") { var parameters = new DynamicParameters(); parameters.Add("@ID", info.ID); parameters.Add("@Institute_Name", info.Institute_Name); parameters.Add("@Office_No", info.Office_No); parameters.Add("@Cell_No", info.Cell_No); parameters.Add("@email", info.email); parameters.Add("@Institute_address", info.Institute_address); parameters.Add("@monogramPath", info.monogramPath); using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionID)); return connection.Execute("sp_SaveNewInstitute", parameters, commandType: CommandType.StoredProcedure); }
额外注意点
- 检查存储过程
sp_SaveNewInstitute的参数列表,确保传递的参数和存储过程定义的参数名称、类型完全匹配,避免因参数不匹配导致其他异常。 - 控制器的
Post方法当前返回void,但代码中调用了Ok(result)不会生效,建议修改返回类型为IActionResult:
[Route("Institute/AddNew")] [HttpPost] public IActionResult Post([FromForm] InstituteInfo Newinfo) { try { var fileResult = _fileService.SaveImage(Newinfo.imageFile, 2); if(fileResult != null) { if (fileResult.Item1 == 1) { Newinfo.monogramPath = fileResult.Item2; } var result = _sqlDataAccess.SaveInstitute(Newinfo); return Ok(result); } return BadRequest("文件保存失败"); } catch (Exception ex) { return StatusCode(500, ex.Message); } }
内容的提问来源于stack exchange,提问作者Khuram Jan
相关产品推荐
相关产品推荐

