【问题标题】:Failed to load resource: the server responded with a status of 400 - using @Html.DropDownListFor加载资源失败:服务器响应状态为 400 - 使用 @Html.DropDownListFor
【发布时间】:2021-09-25 19:04:32
【问题描述】:

我正在尝试在我的 .net 核心应用程序中复制以下 Cascading DropDowns tutorial。我正在为我的控制器和服务使用 WebAPI...但是为了简化和更接近本教程,我已将控制器移至客户端。 Controller 中的逻辑与教程中的逻辑非常相似,显然它运行良好,至少可以在页面加载时填充下拉菜单。

我在 Javascript 上有点挣扎(我相信这是 400 错误的原因),并且我使用了一个半定制模型框架,大约 90% 基于教程模型。疯狂的是 Javascript 正在运行(我相信),因为它在 JS 代码中的断点处停止,因为它最初正确填充了页面加载的 3 个下拉菜单。但是,一旦我在 3 个下拉控件中的任何一个中选择了任何项目...而不是调用“on change”事件,它就会触发以下错误:

加载资源失败:服务器响应状态为 400 () [https://localhost:44317/]

如果需要,我可以提供更多代码,但我已经粘贴了我认为问题所在的逻辑症结下方:

==== Index.cshtml 代码如下====

@page
@using Microsoft.Extensions.Configuration
@model MTGCardTracker.Client.Pages.IndexModel
<div id="dropDownListdiv">
    @using (Html.BeginForm("Index", "CascadingDropDownList", FormMethod.Post))
    {
        @Html.DropDownListFor(m => m.CascadingDropDown.FormatId, Model.CascadingDropDown.Formats, "Please select", new { @class = "form-control" })
        @Html.DropDownListFor(m => m.CascadingDropDown.EditionId, Model.CascadingDropDown.Editions, "Please select", new { @class = "form-control" })
        @Html.DropDownListFor(m => m.CascadingDropDown.CardListId, Model.CascadingDropDown.Cards, "Please select", new { @class = "form-control" })
        <input type="submit" value="Submit" />
    }
</div>
@section scripts {
    <script type="text/javascript">
         $(function () {
                         $("#dropDownListdiv").on("change", "select", function () {
                               var value = $(this).val();
                               var id = $(this).attr("id");
                               $.post("@Url.Action("SetDropDrownList")", { type: id, value: value }, function (data) {
                                     switch (id) {
                                         case "FormatId":
                                             PopulateDropDown("#CascadingDropDown_EditionId", data.CascadingDropDown.Editions);
                                             PopulateDropDown("#CascadingDropDown_CardListId", data.CascadingDropDown.Cards);
                                                 break;
                                         case "EditionId":
                                             PopulateDropDown("#CascadingDropDown_CardListId", data.CascadingDropDown.Cards);
                                                 break;
                                      }
                             });
                         });
                     });
        function PopulateDropDown(dropDownId, list) {
            $(dropDownId).empty();
            $(dropDownId).append("<option>Please select</option>")
            $.each(list, function (index, row) {
                if (index == 0) {
                    $(dropDownId).append("<option value='" + row.Value + "' selected='selected'>" + row.Text + "</option>");
                } else {
                    $(dropDownId).append("<option value='" + row.Value + "'>" + row.Text + "</option>")
                }
            });
        }
    </script>
}

下面是我的模型:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;

namespace MTGTracker.DTO
{
    public class CascadingDropDownDTO
    {
        public string FormatId { get; set; }
        public string EditionId { get; set; }
        public string CardListId { get; set; }
        public SelectList Formats { get; set; }
        public SelectList Editions { get; set; }
        public SelectList Cards { get; set; }

        public IEnumerable<FormatDTO> FormatObject { get; set; }
        public IEnumerable<EditionDTO> EditionObject { get; set; }
        public IEnumerable<CardDetailDTO> CardObject { get; set; }

    }
}

下面(在 _Layout.cshtm 中)是 我相信我现在在我的代码中引用 JS 和 Boostrap 文件的唯一地方:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - MTGCardTracker</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />

    <script type="text/javascript" src="~/lib/jquery/dist/jquery.js"></script>
    @*<script src="~/lib/jquery/dist/jquery.min.js"></script>*@

    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">MTGCardTracker</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - MTGCardTracker - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>



    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

========== SetDropDownList ==========

[HttpPost]
public JsonResult SetDropDrownList(string type, int value)
{
    CascadingDropDownDTO model = GetCascadingDropDownListObject(CascadingDropDown);

    switch (type)
    {
        case "FormatId":
        var EditionsList = CascadingDropDown.EditionObject.Where(m => m.FormatId == value).ToList();
        model.Editions = new SelectList(EditionsList, "EditionId", "EditionName");
        var defaultEditionId = EditionsList.Select(m => m.EditionId).FirstOrDefault();
        model.Cards = new SelectList(CascadingDropDown.CardObject.Where(m => m.EditionId == defaultEditionId).ToList(), "CardListId", "Name");
        break;
        case "EditionId":
        model.Cards = new SelectList(CascadingDropDown.CardObject.Where(m => m.EditionId == value).ToList(), "CardListId", "Name");
        break;
    }
    return Json(model);
}

即使在我删除了提交按钮后,以下代码中仍显示令牌。所以它似乎只是与页面和/或下拉列表相关联。

下面是帖子。不确定我是否可以进一步深入了解更多细节,因为我对尝试在浏览器中调试 JS 还是很陌生:

【问题讨论】:

  • 也许您可以通过将 .js 引用放在 head 元素中来测试它,就在 .css 引用下方。我在页面末尾遇到了一些关于 JQuery 引用的问题。
  • 感谢您的建议。我将它们移到了顶部(并更新了上面的代码示例以反映它),并且每当我尝试更改下拉列表时仍然会得到相同的 400 错误。我认为这可能更多是因为我没有在我的 javascript 代码中正确引用下拉对象。但我不知道。
  • 抱歉,我看不到 SetDropDrownList action 。请问可以发一下吗?
  • 更新了代码以添加 SetDropDownList 方法。如果它在控制器中的某个地方出现故障......我至少不应该让代码在调试时在控制器内部中断吗?我在控制器中每个方法的开头都设置了断点......并且在页面初始加载后没有调用任何内容。
  • 页面中是否添加了防伪令牌?然后 Ajax POST 命令应该在其 post 语句中包含该标记,否则将返回 400 错误。 mikesdotnetting.com/article/336/…

标签: javascript c# asp.net asp.net-mvc dropdown


【解决方案1】:

好的,所以对我来说答案是几件事,但下面的部分可能是最关键的。我需要将“endpoints.MapControllerRoute ...”行添加到我的 Startup.cs configure() 方法中:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllers();

        endpoints.MapControllerRoute(name: "CascadingDropDownList", pattern: "{controller=CascadingDropDownList}/{action=Index}/{id?}");
    });

这让我的控制器被看到了。

我还需要修改我的 JS 以解决控件 ID 名称的更改,因为我使用的是与教程不同的半自定义嵌套模型类,并将 $.post 调用从操作更改为带有控制器名称和方法调用:

<script>
    src = "https://code.jquery.com/jquery-3.5.1.min.js" >
        /*CODE FOR THE CASCADING DROP DOWNS*/
        $(function () {
            $("#dropDownListdiv").on("change", "select", function () {

                var id = $(this).attr("id");
                var value = $(this).val();
                alert($(this).attr("id"));
                alert($(this).val());
                alert("Executing POST...");
                $.post('/CascadingDropDownList/SetDropDrownList', { type: id, value: value }, function (data) {
                    switch (id) {
                        case "cascadingDropDown_FormatId":
                            PopulateDropDown("#cascadingDropDown_EditionId", data.Editions);
                            PopulateDropDown("#cascadingDropDown_CardListId", data.Cards
                            break;
                        case "cascadingDropDown_EditionId":
                            PopulateDropDown("#cascadingDropDown_CardListId", data.Cards);
                            break;
                    }
                });
            });
            alert("Exited Main Function");
        });

    function PopulateDropDown(dropDownId, list) {
        alert("Entered PopulateDropDown...");
        alert("dropDownId: " + dropDownId);
        $(dropDownId).empty();
        $(dropDownId).append("<option>Please select</option>")
        alert("Running ForEach...");
        $.each(list, function (index, row) {
            if (index == 0) {
                $(dropDownId).append("<option value='" + row.Value + "' selected='selected'>" + row.Text + "</option>");
            } else {
                $(dropDownId).append("<option value='" + row.Value + "'>" + row.Text + "</option>")
            }
        });
        alert("Exited PopulateDropDown...");
    }
</script>

现在我的 SetDropDownList 方法被正确调用了。虽然我的下拉列表没有被正确填充,但它们被 JS 调用重置为空,所以我知道我至少正确地定位了它们。接下来要弄清楚为什么他们没有得到正确的新过滤子集列表。

希望这对其他人有所帮助。我认为主要问题是我不熟悉 MVC 与 Razor MVC 以及它们附带的所有基本原理和细微差别。

【讨论】:

    猜你喜欢
    • 2021-04-12
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    • 2020-10-20
    • 2021-08-26
    • 2020-02-14
    • 2016-11-01
    • 2018-01-29
    相关资源
    最近更新 更多