MVC3 AJAX级联下拉列表

3
我在asp.net mvc3应用程序中很难想出如何使级联下拉列表起作用。我有一个弹出框,我想显示两个下拉列表,第二个下拉列表是基于第一个下拉列表所选内容填充的。每次运行应用程序时,控制器方法返回正确的值列表,但我没有命中ajax调用的成功部分,而是错误部分。我进行了大量研究并遵循了几个例子,但仍然存在问题,任何帮助将不胜感激。
编辑: 使用火狐浏览器检查后,显示内部服务器错误500 Exception Details: System.InvalidOperationException:在序列化类型为'System.Data.Entity.DynamicProxies.GameEdition'的对象时检测到循环引用
以下是我的jQuery / AJAX代码:
<script type="text/javascript">
$(function () {
    $("#PlatformDropDownList").change(function () {
        var gameId = '@Model.GameID';
        var platformId = $(this).val();
        // and send it as AJAX request to the newly created action 
        $.ajax({
            url: '@Url.Action("Editions")',
            type: 'GET',
            data: { gameId: gameId, platformId: platformId },
            cache: 'false',
            success: function (result) {
                $('#EditionDropDownList').empty();
                // when the AJAX succeeds refresh the ddl container with 
                // the partial HTML returned by the PopulatePurchaseGameLists controller action 
                $.each(result, function (result) {
                    $('#EditionDropDownList').append(
                        $('<option/>')
                            .attr('value', this.EditionID)
                            .text(this.EditionName)
                    );

                });
            },
            error: function (result) {
                alert('An Error has occurred');
            }
        });
    });
});

这是我的控制器方法:
  public JsonResult Editions(Guid platformId, Guid gameId)
  {
     //IEnumerable<GameEdition> editions = GameQuery.GetGameEditionsByGameAndGamePlatform(gameId, platformId);
     var editions = ugdb.Games.Find(gameId).GameEditions.Where(e => e.PlatformID == platformId).ToArray<GameEdition>();

     return Json(editions, JsonRequestBehavior.AllowGet);
  }

这是我的网页表单HTML代码:
<div id="PurchaseGame">
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true, "Please correct the errors and try again.")
    <div>
        <fieldset>
            <legend></legend>
            <p>Select the platform you would like to purchase the game for and the version of the game you would like to purchase.</p>

            <div class="editor-label">
                @Html.LabelFor(model => model.PlatformID, "Game Platform")
            </div>
            <div class="editor-field">
                @Html.DropDownListFor(model => model.PlatformID, new SelectList(Model.Platforms, "GamePlatformID", "GamePlatformName"), new { id = "PlatformDropDownList", name="PlatformDropDownList" })
            </div>

            <div class="editor-label">
                @Html.LabelFor(model => model.EditionID, "Game Edition")
            </div>
            <div id="EditionDropDownListContainer">
                @Html.DropDownListFor(model => model.EditionID, new SelectList(Model.Editions, "EditionID", "EditionName"), new { id = "EditionDropDownList", name = "EditionDropDownList" })
            </div>

            @Html.HiddenFor(model => model.GameID)
            @Html.HiddenFor(model => model.Platforms)

            <p>
                <input type="submit" name="submitButton" value="Purchase Game" />
                <input type="submit" name="submitButton" value="Cancel" />
            </p>

        </fieldset>
    </div>
}

1个回答

4
您不能使用GET动词发送JSON编码的请求。因此,请用type: 'POST'替换type: 'GET',这样它就能工作了。另外,既然您已经指定了一个JSON请求,您必须发送一个JSON请求,这可以通过JSON.stringify函数实现:data: JSON.stringify({ gameId: gameId, platformId: platformId }),。但由于您只有2个值,我认为使用GET会更容易。因此,我的建议是删除contentType: 'application/json'参数,并让您的AJAX请求看起来像这样:
$.ajax({
    url: '@Url.Action("Editions")',
    type: 'GET',
    data: { gameId: gameId, platformId: platformId },
    cache: 'false',
    success: function (result) {
        $('#EditionDropDownList').empty();
        // when the AJAX succeeds refresh the ddl container with 
        // the partial HTML returned by the PopulatePurchaseGameLists controller action 
        if(result.length > 0)
        {
            $.each(result, function (result) {
                $('#EditionDropDownList').append(
                    $('<option/>')
                         .attr('value', this.EditionID)
                         .text(this.EditionName)
                );
            });
        }
        else
        {
            $('#EditionDropDownList').append(
                $('<option/>')
                    .attr('value', "")
                    .text("No edition found for this game")
            );
        }

    },
    error: function () {
        alert('An Error has occured');
    }
});

同时,在您的 Razor 标记中,DropDownListFor 助手中我注意到以下内容:

onchange = "Model.PlatformID = this.value;"

我能说的是,这并不做你可能想象的事情。
更新:
看起来你会收到一个循环对象引用错误,因为你正在将你的“editions”域模型传递给Json方法。循环引用对象层次结构不能被JSON序列化。此外,你没有必要通过向客户端发送包含在这些版本中的所有废物来浪费带宽。你的客户端只需要一个ID和名称的集合。所以只需使用视图模型即可。
public ActionResult Editions(Guid platformId, Guid gameId)
{
    var editions = ugdb
        .Games
        .Find(gameId)
        .GameEditions
        .Where(e => e.PlatformID == platformId)
        .ToArray<GameEdition>()
        .Select(x => new 
        {
            EditionID = x.EditionID,
            EditionName = x.EditionName
        })
        .ToArray();

    return Json(editions, JsonRequestBehavior.AllowGet);
}

非常感谢您的反馈。我已经实现了您的建议,但仍然无法进入JavaScript的成功部分,而是进入了错误部分。我也尝试过使用JSON.stringify并将控制器方法和类型更改为“POST”,但得到了相同的错误结果。同时,我删除了onchange,因为您是正确的,它没有执行我期望的操作。我已经更新了我的帖子,添加了修改后的代码。 - Aaron Davis
控制器动作是否被调用?它是否在没有异常的情况下运行?您在FireBug中看到了什么?服务器对AJAX请求发送了什么响应? - Darin Dimitrov
控制器操作能够成功调用,没有异常,而且 "editions" 变量中包含了正确的值。但我注意到我得到了一个内部服务器500错误,说关于循环引用的问题。我更新了我的文章,更详细地包括了这个错误信息。我进行了一些研究,从我的理解来看,这通常是由于json返回未被正确格式化或读取所导致的,但我不确定如何修复它。 "editions" 变量确实指向 GameEdition 实体对象的列表,因此可能无法正确处理它。 - Aaron Davis
是的,这很清楚。您无法对循环对象引用层次结构进行JSON序列化。您将需要使用视图模型。摆脱此版本变量并定义一个不包含循环引用的视图模型,然后将此视图模型的实例传递给您返回的Json方法。您只需要包含消费者需要的信息,而不是整个域模型。而且您只需要一个包含ID和名称的模型集合。我已更新我的帖子以向您展示示例。 - Darin Dimitrov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接