.NET 5 MVC提交表单至Action时出现404错误求助
提交患者评估数据时出现404错误问题
我有一个基于SPEPatientEvalVM视图模型的患者评估数据提交页面,页面显示正常,但填写完必填字段点击提交按钮时出现404错误,请求地址为https://localhost:5001/SPE/AddSPEPatientEval/18659/15129/235/4。已尝试为HttpPost添加路由、确保模型字段非空等操作,问题仍未解决。以下是相关代码:
SPEPatientEvalVM 视图模型
public class SPEPatientEvalVM { public int Id { get; set; } public int ApptId { get; set; } public int ActivityID { get; set; } public int VendorID { get; set; } public int PatientID { get; set; } [Required(ErrorMessage ="A selection is required.")] public int OverallRating { get; set; } [Required(ErrorMessage = "A selection is required.")] public int AppearProfessComp { get; set; } [Required(ErrorMessage = "A selection is required.")] public int EffGatheredInfo { get; set; } [Required(ErrorMessage = "A selection is required.")] public int ListenActively { get; set; } [Required(ErrorMessage = "A selection is required.")] public int EstabPersRapport { get; set; } [Required(ErrorMessage = "A selection is required.")] public int AppropExploreMyFeelings { get; set; } [Required(ErrorMessage = "A selection is required.")] public int AddressedMyFeelings { get; set; } [Required(ErrorMessage = "A selection is required.")] public int MetMyNeeds { get; set; } public string PatientComments { get; set; } = String.Empty; public DateTime DateSubmitted { get; set; } }
该ViewModel通过IMapper与实体模型双向映射。
Controller 代码
[HttpGet("[controller]/[action]/{IDAppt}/{ActivityID}/{VendorID}/{PatientID}")] public async Task<IActionResult> AddSPEPatientEval(int IDAppt, int ActivityID, int VendorID, int PatientID) { var patientChoice = GetPatientChoiceList(); patientChoice[0].Selected = true; ViewBag.PatientChoice = patientChoice; var evalParams = await _speRepo.GetOpenPatientEval(IDAppt); ViewBag.Patient = evalParams.SPEPatient; var speEval = new SPEPatientEvalVM { ApptId = IDAppt, ActivityID = ActivityID, VendorID = VendorID, PatientID = PatientID }; return View(speEval); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> AddSPEPatientEval(SPEPatientEvalVM model) { var patientChoice = GetPatientChoiceList(); patientChoice[0].Selected = true; ViewBag.PatientChoice = patientChoice; model.DateSubmitted = DateTime.Now; if (ModelState.IsValid) { var spePatientEval = _mapper.Map<SPEPatientEval>(model); var success = await _speRepo.AddSPEPatientEval(spePatientEval); if (!success) { return View(model); } return View("Index"); } return View(model); }
View (AddSPEPatientEval.cshtml) 代码
@model SPEPatientEvalVM @{ ViewData["Title"] = "AddSPEPatientEval"; } <div class="col-md-8 m-auto"> <h1 class="text-center">Patient SPE Evaluation</h1> <hr /> </div> <div class="col-md-8 m-auto"> <div class="row"> <div class="col-md-12"> <form asp-controller="SPE" asp-action="AddSPEPatientEval" method="post"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <input type="hidden" asp-for="ApptId" /> <input type="hidden" asp-for="ActivityID" /> <input type="hidden" asp-for="VendorID" /> <input type="hidden" asp-for="PatientID" /> <input type="hidden" asp-for="DateSubmitted" value="@String.Format("{0:MM/dd/yyyy}", DateTime.Now)" /> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="OverallRating" class="control-label">As @ViewBag.Patient, rate your overall level of satisfaction with this encounter.</label> <select asp-for="OverallRating" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="OverallRating" class="text-danger"></span> </div> <br /> <hr /> </div> </div> <br /> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="AppearProfessComp" class="control-label">Appeared professional competent - seemed to know what s/he was doing; inspired my comfidence; appeared to have my interests at heart. </b></label> <select asp-for="AppearProfessComp" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="AppearProfessComp" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="EffGatheredInfo" class="control-label">Effectively gathered information - collected information in a way that seemed organized; began with several open-ended questions and progressed through interview using a balanced ratio of open- to closed-ended questions; summarized periodically. </label> <select asp-for="EffGatheredInfo" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="EffGatheredInfo" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="ListenActively" class="control-label">Listened actively - paid attention to both my verbal and non-verbal cues; used facial expressions/body language to express encouragement; avoided interruptions; asked questions to make sure s/he understood what I said. </label> <select asp-for="ListenActively" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="ListenActively" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label class="control-label">Established personal rapport - introduced self warmly; verbally/non-verbally showed interest in me as a person, not just my condition; avoided technical jargon. </label> <select asp-for="EstabPersRapport" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="EstabPersRapport" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="AppropExploreMyFeelings" class="control-label">Appropriately explored my perspective - encouraged me to identify everything that I needed to say. </label> <select asp-for="AppropExploreMyFeelings" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="AppropExploreMyFeelings" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="AddressedMyFeelings" class="control-label">Addressed my feelings - acknowledged and demonstrated interest in my expressed and/orunexpressed feelings and experience. </label> <select asp-for="AddressedMyFeelings" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="AddressedMyFeelings" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="MetMyNeeds" class="control-label">Met my needs - worked toward a plan which addressed both the diagnosis and my concerns about my illness. </label> <select asp-for="MetMyNeeds" class="form-control" asp-items="@(new SelectList(ViewBag.PatientChoice, "Value", "Text"))"></select> <span asp-validation-for="MetMyNeeds" class="text-danger"></span> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <label asp-for="PatientComments" class="control-label"></label> <textarea asp-for="PatientComments" class="form-control" placeholder="Please add any additional comments you would like to express about this examination."></textarea> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="form-group"> <input type="submit" value="Submit" class="btn btn-primary" /> </div> </div> </div> </form> </div> </div> </div> <div class="row"> <div class="col-md-8 m-auto"> <div class="text-center"> <a asp-action="Index">Back to List</a> </div> </div> </div> @section Scripts { @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } }
问题原因及解决方案
原因
表单提交时生成的URL携带了Get方法的路由参数(/18659/15129/235/4),但Post方法没有匹配该带参数路由的配置,导致请求找不到对应的处理方法,触发404错误。
解决方案
方案1:给Post方法添加匹配参数的路由
修改Post方法的路由属性,让它能接收带参数的请求,同时不影响模型绑定:
[HttpPost("[controller]/[action]/{IDAppt:int?}/{ActivityID:int?}/{VendorID:int?}/{PatientID:int?}")] [ValidateAntiForgeryToken] public async Task<IActionResult> AddSPEPatientEval(SPEPatientEvalVM model) { // 原有逻辑保持不变 var patientChoice = GetPatientChoiceList(); patientChoice[0].Selected = true; ViewBag.PatientChoice = patientChoice; model.DateSubmitted = DateTime.Now; if (ModelState.IsValid) { var spePatientEval = _mapper.Map<SPEPatientEval>(model); var success = await _speRepo.AddSPEPatientEval(spePatientEval); if (!success) { return View(model); } return View("Index"); } return View(model); }
这里给路由参数添加int?标记为可选,确保不带参数的Post请求也能匹配。
方案2:修改表单,提交到不带参数的地址
调整form标签,明确指定提交地址为不带参数的路由,避免沿用Get方法的参数格式:
<form asp-controller="SPE" asp-action="AddSPEPatientEval" method="post" asp-route-IDAppt="" asp-route-ActivityID="" asp-route-VendorID="" asp-route-PatientID="">
或者直接手动指定action属性:
<form action="/SPE/AddSPEPatientEval" method="post">
这样表单提交时会发送到/SPE/AddSPEPatientEval,匹配现有的Post方法路由。
额外优化
View中手动给DateSubmitted隐藏字段赋值了格式化日期,但控制器里又重新设置了model.DateSubmitted = DateTime.Now;,建议删除View中的该隐藏字段赋值,统一由控制器处理,避免逻辑冲突。
内容的提问来源于stack exchange,提问作者Chris Woodard
相关产品推荐
相关产品推荐

