ASP.NET Core MVC提交表单调用其他控制器时模型未更新问题
问题描述
我有一个供用户更新信息的表单,当用户选择“Request Invoice”时,应将更新后的模型传递到指定控制器进行处理。路由功能正常,但目前仍在向控制器发送旧模型而非更新后的模型。我刚接触ASP.NET Core MVC,希望能得到帮助与指导。
我的视图代码
@model xxx.Models.Modules @{ ViewData["Title"] = "Manage Module"; } <h1>Edit</h1> <h4>Modules</h4> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Edit"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <input type="hidden" asp-for="Id" /> <div class="form-group"> <label asp-for="ModuleName" class="control-label"></label> <input asp-for="ModuleName" class="form-control" readonly/> <span asp-validation-for="ModuleName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="NumberOfLicenses" class="control-label"></label> <input asp-for="NumberOfLicenses" class="form-control" /> <span asp-validation-for="NumberOfLicenses" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="NumberOfLicensesUsed" class="control-label"></label> <input asp-for="NumberOfLicensesUsed" class="form-control" /> <span asp-validation-for="NumberOfLicensesUsed" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="NumberOfLicesesAvailable" class="control-label"></label> <input asp-for="NumberOfLicesesAvailable" class="form-control" readonly/> <span asp-validation-for="NumberOfLicesesAvailable" class="text-danger"></span> </div> <input type="hidden" asp-for="CompanyId" /> <div class="form-group"> <input type="submit" value="Request Invoice" class="btn btn-primary" onclick="location.href='@Url.Action("CreateInvoice","XeroOAuth2",Model)'" /> <input type="submit" value="Request Quote" class="btn btn-primary" onclick="location.href='@Url.Action("RequestQoute","XeroOAuth2",Model)'" /> </div> </form> </div> </div> <div> <a asp-action="Index">Back to List</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
我的模型代码
using System.ComponentModel.DataAnnotations; namespace xxx.Models { public class Modules { [Key] public int Id { get; set; } public string ModuleName { get; set; } public int NumberOfLicenses { get; set; } public int NumberOfLicensesUsed { get; set; } public int NumberOfLicesesAvailable { get; set; } public int CompanyId { get; set; } public virtual Company Company { get; set; } } }
我的控制器操作方法
public async Task<IActionResult> CreateInvoice(Modules modules) { var client = new XeroClient(xconfig); await _xero.CreateInvoice(xconfig, modules); return RedirectToAction("Index", "Home"); }
预期结果:在视图中修改NumberOfLicenses后,点击“Request Invoice”按钮,应将新模型传递到控制器。
问题原因
按钮使用onclick="location.href='@Url.Action(...)"的方式跳转时,@Url.Action是在页面首次渲染时生成的URL,其中携带的Model是初始加载的旧数据。用户修改表单内容后,这个URL不会自动更新,因此跳转时传递给控制器的始终是页面加载时的旧模型值,而非用户输入的新内容。同时,这种方式本质是GET跳转,根本没有提交表单,控制器无法获取表单中修改后的字段值。
解决方案
方案一:使用表单提交传递更新后的数据(推荐)
利用ASP.NET Core的formaction属性,让不同按钮提交到不同的控制器动作,表单会自动携带所有输入字段的最新值:
- 修改视图中的按钮部分,移除
onclick事件,添加formaction属性:
<div class="form-group"> <input type="submit" value="Request Invoice" class="btn btn-primary" formaction="@Url.Action("CreateInvoice","XeroOAuth2")" /> <input type="submit" value="Request Quote" class="btn btn-primary" formaction="@Url.Action("RequestQoute","XeroOAuth2")" /> </div>
- 给控制器动作添加
[HttpPost]属性(表单默认以POST方式提交,确保控制器能接收):
[HttpPost] public async Task<IActionResult> CreateInvoice(Modules modules) { // 可选:重新计算可用许可证数量,避免依赖表单传递的旧值 modules.NumberOfLicesesAvailable = modules.NumberOfLicenses - modules.NumberOfLicensesUsed; var client = new XeroClient(xconfig); await _xero.CreateInvoice(xconfig, modules); return RedirectToAction("Index", "Home"); }
方案二:用JavaScript收集表单数据(适合需要前端逻辑的场景)
如果需要在提交前处理前端逻辑,可以通过JS获取表单的最新值,再构造请求:
<script> function submitToAction(actionUrl) { // 收集表单中的最新值 var formData = new FormData(document.querySelector('form')); // 发送POST请求 fetch(actionUrl, { method: 'POST', body: formData, headers: { 'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value } }).then(response => { if (response.ok) { window.location.href = '@Url.Action("Index", "Home")'; } }); // 阻止默认提交行为 return false; } </script> <!-- 修改按钮为普通按钮,绑定JS函数 --> <div class="form-group"> <button type="button" class="btn btn-primary" onclick="submitToAction('@Url.Action("CreateInvoice","XeroOAuth2")')">Request Invoice</button> <button type="button" class="btn btn-primary" onclick="submitToAction('@Url.Action("RequestQoute","XeroOAuth2")')">Request Quote</button> </div>
注意事项
- 对于
readonly的字段(如NumberOfLicesesAvailable),建议在控制器中重新计算,不要依赖表单传递的值,避免数据不一致或被篡改。 - 确保表单包含防伪令牌(ASP.NET Core默认会生成,通过
_ValidationScriptsPartial或自动注入),防止跨站请求伪造(CSRF)。
内容的提问来源于stack exchange,提问作者MarkBerry
相关产品推荐
相关产品推荐

