You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(&quot;CreateInvoice&quot;,&quot;XeroOAuth2&quot;,Model)'" />
                <input type="submit" value="Request Quote" class="btn btn-primary" onclick="location.href='@Url.Action(&quot;RequestQoute&quot;,&quot;XeroOAuth2&quot;,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属性,让不同按钮提交到不同的控制器动作,表单会自动携带所有输入字段的最新值:

  1. 修改视图中的按钮部分,移除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>
  1. 给控制器动作添加[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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 09:14:59