ASP.NET MVC部署IIS后输入字符串格式错误排查与优化
ASP.NET MVC部署IIS后「输入字符串格式不正确」问题排查与解决
开发ASP.NET MVC应用时,本地运行正常,但部署到IIS后出现FormatException(输入字符串格式不正确),无法确定触发原因和具体代码行,以下是针对性的排查、优化与修复方案:
一、错误原因排查
- Session值类型不匹配:代码中直接调用
Convert.ToInt32(Session[SessionKeys.UserCode]),若Session存储的不是可转换为int的内容,或IIS会话配置导致Session值异常,会触发格式错误。 - 可空类型的不安全操作:
LineManager是int?类型,代码中多次直接调用ToString()或Convert.ToInt32(),未判断是否为null,可能引发转换异常。 - 模型属性缺失:Action中频繁使用
resignationRequester.DirectManager,但ResignationRequester模型未定义该属性,导致其值为null,调用Convert.ToInt32(null)会抛出FormatException。 - 前端输入未校验:自动补全组件在无匹配结果时,返回用户输入的原始文本作为
value,若用户提交非数字内容,会导致模型绑定或转换失败。 - 环境差异:本地与IIS的区域设置、Session存储模式不同,可能导致值的格式或有效性差异。
二、优化代码以显示清晰错误信息&避免错误
- 捕获详细异常信息:在catch块中返回堆栈跟踪,同时记录日志:
catch (FormatException ex) { responseData.success = false; responseData.message = $"格式错误:{ex.Message},错误位置:{ex.StackTrace}"; // 写入日志文件(生产环境建议用专业日志框架) System.IO.File.AppendAllText(Server.MapPath("~/Logs/error.log"), $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 错误详情:{ex.ToString()}\n"); }
- 使用安全转换方法:替换
Convert.ToInt32为int.TryParse,提前处理无效值:
if (!int.TryParse(Session[SessionKeys.UserCode]?.ToString(), out int empId)) { responseData.message = "用户ID格式无效,请重新登录"; return Json(responseData); } resignationRequester.EmpID = empId;
- 安全访问可空类型:通过
HasValue判断后再操作,避免空引用或转换错误:
if (resignationRequester.LineManager.HasValue) { string lineManagerStr = resignationRequester.LineManager.Value.ToString(); if (lineManagerStr.Length < 6) { responseData.message = "Line Manager编号长度必须≥6"; return Json(responseData); } }
- 提前检查ModelState:在修改模型属性前验证绑定有效性,返回具体绑定错误:
if (!ModelState.IsValid) { var errors = ModelState.Values .SelectMany(v => v.Errors) .Select(e => string.IsNullOrEmpty(e.ErrorMessage) ? e.Exception.Message : e.ErrorMessage); responseData.message = string.Join(";", errors); return Json(responseData); }
三、定位触发错误的代码行
- 输出异常堆栈:在catch块中返回
ex.StackTrace,直接获取错误发生的代码行号。 - 启用IIS详细错误:临时在web.config中设置
<customErrors mode="Off"/>(仅调试环境),浏览器会显示完整错误页面,包含具体代码行。 - 添加调试日志:在关键转换代码前后写入日志,追踪变量值:
System.IO.File.AppendAllText(Server.MapPath("~/Logs/debug.log"), $"[{DateTime.Now}] Session UserCode: {Session[SessionKeys.UserCode]}\n" + $"LineManager值: {resignationRequester.LineManager}\n");
四、修正代码中的错误解析逻辑
核心问题修复:
- 补充缺失的模型属性:在
ResignationRequester中添加DirectManager属性:
public class ResignationRequester { [Display(Name = "Employee No : ")] [Required] public int EmpID { get; set; } [Display(Name = "Line Manager: ")] public int? LineManager { get; set; } // 添加缺失的DirectManager属性 public int? DirectManager { get; set; } }
- 重构Action中的验证逻辑:替换不安全转换,修正逻辑矛盾:
[HttpPost] public JsonResult RequesterIndex(ResignationRequester resignationRequester) { dynamic responseData = new ExpandoObject(); responseData.success = false; responseData.message = ""; try { // 校验Session有效性 if (Session[SessionKeys.UserCode] == null) { responseData.message = "会话已过期,请重新登录"; return Json(responseData); } // 安全转换Session用户ID if (!int.TryParse(Session[SessionKeys.UserCode]?.ToString(), out int empId)) { responseData.message = "用户ID格式无效,请重新登录"; return Json(responseData); } resignationRequester.EmpID = empId; // 模型绑定校验 if (!ModelState.IsValid) { var errorMessages = ModelState.Values .SelectMany(v => v.Errors) .Select(e => string.IsNullOrEmpty(e.ErrorMessage) ? e.Exception?.Message : e.ErrorMessage); responseData.message = string.Join(";", errorMessages); return Json(responseData); } // LineManager非空校验与长度校验 if (!resignationRequester.LineManager.HasValue) { responseData.message = "Line Manager不能为空"; return Json(responseData); } string lineManagerStr = resignationRequester.LineManager.Value.ToString(); if (lineManagerStr.Length < 6) { responseData.message = "Line Manager编号长度必须≥6"; return Json(responseData); } // DirectManager非空校验 if (!resignationRequester.DirectManager.HasValue) { responseData.message = "Direct Manager不能为空"; return Json(responseData); } // 申请人与经理编号重复校验 if (resignationRequester.EmpID == resignationRequester.DirectManager.Value && resignationRequester.EmpID == resignationRequester.LineManager.Value) { responseData.message = "申请人编号不能与Line Manager、Direct Manager编号相同"; return Json(responseData); } // 业务逻辑执行 if (string.IsNullOrEmpty(ViewBag.errorMsg)) { responseData.success = true; responseData.message = "辞职申请表提交成功"; return Json(responseData); } responseData.message = ViewBag.errorMsg; } catch (Exception ex) { responseData.message = $"提交失败:{ex.Message}"; System.IO.File.AppendAllText(Server.MapPath("~/Logs/error.log"), $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 错误详情:{ex.ToString()}\n"); } return Json(responseData); }
- 前端输入校验优化:禁止选择无效选项,清空非法输入:
$("#txtLineManagerId").autocomplete({ source: function (request, response) { var searchText = $("#txtLineManagerId").val(); $.ajax({ url: '@Url.Action("GetAllEmployeeBasedSearchText", "Resignation")', data: { searchText: searchText }, method: "GET", dataType: "json", success: function (data) { if (!data.length) { response([]); alert("未找到匹配的员工,请重新输入"); } else { response($.map(data, function (item) { return { label: `File No : ${item.EmployeeID} - Name : ${item.EmployeeName} - Designation : ${item.Designation}`, value: item.EmployeeID, employeeName: item.EmployeeName, designation: item.Designation }; })); } } }); }, position: { my: "right top", at: "right bottom" }, appendTo: '#searchContainer', select: function (event, ui) { $("#LineManagerName").val(ui.item.employeeName); }, minLength: 2, change: function(event, ui) { // 未选择有效选项时清空输入 if (!ui.item) { $("#txtLineManagerId").val(""); $("#LineManagerName").val(""); alert("请选择有效的Line Manager"); } } }).data("ui-autocomplete")._renderItem = function (ul, item) { return $("<li>") .append(`<div>File No: ${item.value}<br/>Name: ${item.employeeName}<br/>Designation: ${item.designation}</div>`) .appendTo(ul); };
内容的提问来源于stack exchange,提问作者ahmed abdelaziz
相关产品推荐
相关产品推荐

