Ajax 调用返回旧的 ASP.NET MVC 部分视图而不是更新的视图

问题描述

我有一个由按钮触发的 Ajax 调用,它调用控制器来更新局部视图。控制器返回更新后的局部视图,但是Ajax调用的成功函数中接收到的局部视图是原始视图,而不是更新后的视图。

我创建了一个示例 ASP.NET MVC 程序来重现该问题。该程序在表格中显示客户列表,如下所示。

Snapshot of UI

文本框在局部视图_Status 中呈现。当点击切换状态按钮时,通过Ajax调用控制器来切换客户的状态真假,并刷新对应文本框的局部视图。问题是状态永远不会改变。这是为什么?

更新

我刚刚在控制器的Status action中添加了下面这行代码,现在Ajax成功函数正确接收到更新后的局部视图!

this.ModelState.Clear();

谁能解释一下原因?

这是显示初始视图的 Index.cshtml 视图。

@model IEnumerable<ComboModel.Models.CustomerSummary>

<script type="text/javascript">
    function updatePartialView(id) {
        debugger;
        $.ajax({
            url: "/CustomerSummary/Status",data: $('#' + id + ' :input').serialize(),dataType: "HTML",type: "POST",success: function (partialView) {
                // Here the received partial view is not the one created in
                // the controller,but the original view. Why is that?
                debugger;
                $('#' + id).replaceWith(partialView);
            },error: function (err) {
                debugger;
            },failure: function (err) {
                debugger;
            }
        });
    }
</script>

<h2>Customer Summary</h2>
<table>
    <tr>
        <th>Name</th>
        <th>Active?</th>
        <th>Toggle</th>
    </tr>

    @foreach (var summary in Model)
    {
        <tr>
            <td>@summary.FirstName @summary.LastName</td>
            @Html.Partial("_Status",summary.Input)
            <td><button type="button" name="@("S" + summary.Input.Number)" onclick="updatePartialView(this.name)">Toggle Status</button></td>
        </tr>
    }
</table>

_Status.cshtml 部分视图。

@model ComboModel.Models.CustomerSummary.CustomerSummaryInput

<td id="@("S" + Model.Number)">
    @Html.TextBoxFor(model => model.Active)
    <input type="hidden" value="@Model.Number" name="Number" />
</td>

CustomerSummaryController.cs。

using System.Collections.Generic;
using System.Web.Mvc;
using ComboModel.Models;

namespace ComboModel.Controllers
{
    public class CustomerSummaryController : Controller
    {
        private readonly CustomerSummaries _customerSummaries = new CustomerSummaries();

        public ViewResult Index()
        {
            IEnumerable<CustomerSummary> summaries = _customerSummaries.GetAll();
            return View(summaries);
        }

        public PartialViewResult Status(CustomerSummary.CustomerSummaryInput input)
        {
            this.ModelState.Clear(); // If I add this,things work. Why?
            input.Active = input.Active == "true" ? "false" : "true";
            return PartialView("_Status",input);
        }
    }

    public class CustomerSummaries
    {
        public IEnumerable<CustomerSummary> GetAll()
        {
            return new[]
            {
                new CustomerSummary
                {
                    Input = new CustomerSummary.CustomerSummaryInput {Active = "true",Number = 0},FirstName = "John",LastName = "Smith"
                },new CustomerSummary
                {
                    Input = new CustomerSummary.CustomerSummaryInput {Active = "false",Number = 1},FirstName = "Susan",LastName = "Power"
                },new CustomerSummary
                {
                    Input = new CustomerSummary.CustomerSummaryInput {Active = "true",Number = 2},FirstName = "Jim",LastName = "Doe"
                },};
        }
    }
}

最后是 CustomerSummary.cs 模型。

namespace ComboModel.Models
{
    public class CustomerSummary
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public CustomerSummaryInput Input { get; set; }

        public class CustomerSummaryInput
        {
            public int Number { get; set; }
            public string Active { get; set; }
        }
    }
}

谢谢!

解决方法

这是 Asp.net MVC ModelState.Clear 的副本。

在当前场景下,因为没有验证status字段,所以清除ModelState就可以了。但是,MVC 的正确方法是将状态值(true 或 false)传递给控制器​​中的 GET 操作,切换该值,返回结果字符串,并更新页面上的文本框。