【问题标题】:Using AJAX call in MVC5在 MVC5 中使用 AJAX 调用
【发布时间】:2016-12-24 07:45:45
【问题描述】:

我曾尝试在 MVC5 项目中使用 AJAX 调用,就像网络上的许多类似示例一样,但每次出现错误时,例如 antiforgerytoken、500 等。我正在寻找一个适当的 AJAX 调用方法和控制器操作方法具有所有必要的属性并将模型数据从 View 发送到 Controller Action。以下是我使用的方法:

查看:

@using (Html.BeginForm("Insert", "Account", FormMethod.Post, new { id = "frmRegister" })) 
{
    @Html.AntiForgeryToken()
    //code omitted for brevity
}



<script>

    AddAntiForgeryToken = function (data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
    };

$('form').submit(function (event) {
        event.preventDefault();

        //var formdata = JSON.stringify(@Model); //NOT WORKING???
        var formdata = new FormData($('#frmRegister').get(0));
        //var token = $('[name=__RequestVerificationToken]').val(); //I also tried to use this instead of "AddAntiForgeryToken" method but I encounter another error

        $.ajax({
            type: "POST",
            url: "/Account/Insert",
            data: AddAntiForgeryToken({ model: formdata }),
            //data: { data: formdata, __RequestVerificationToken: token },
            //contentType: "application/json",
            processData: false,
            contentType: false,

            datatype: "json",
            success: function (data) {
                $('#result').html(data);
            }
        });

    });
</script>

Controller: 由于 antiforgerytoken 或类似问题,代码无法命中此 Action 方法。

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public JsonResult Insert(RegisterViewModel model)
{
    try
    {
         //...
         //code omitted for brevity
    }
}

我只需要一个适当的 AJAX 和 Action 方法,它们可以用于 MVC5 中的 CRUD 操作。任何帮助将不胜感激。

更新:以下是我需要澄清的几点:

1)我们没有使用“__RequestVerificationToken”,我不确定我们是否正确地将它发送到控制器(它似乎是 Firebug 的请求标头中的 cookie,但我不确定它是否可以)。任何想法?

2) 我应该使用 var formdata = new FormData($('#frmRegister').get(0));当我上传文件?

3) 为什么我必须避免在这种情况下使用 processData 和 contentType?

4) AJAX方法的Controller方法和错误部分是否OK?还是那里有任何遗漏或多余的部分?

【问题讨论】:

  • 使用var formdata = new FormData($('#frmRegister').get(0)); 将包含防伪令牌。你只需要data: formdata, 虽然不清楚你为什么使用FormData(你也在上传文件吗?)

标签: javascript jquery asp.net ajax asp.net-mvc


【解决方案1】:

如果您视图中的模型是RegisterViewModel,并且您已使用强类型HtmlHelper 方法正确生成了表单控件,那么使用new FormData($('#frmRegister').get(0))$('#frmRegister').serialize() 将正确发送其中所有表单控件的值&lt;form&gt;标签,包括token,不需要再次添加token。

如果你的表单不包含文件输入,那么代码应该是

$('form').submit(function (event) {
    event.preventDefault();
    var formData = $('#frmRegister').serialize();
    $.ajax({
        type: "POST",
        url: '@Url.Action("Insert", "Account")', // do not hard code your url's
        data: formData,
        datatype: "json", // refer notes below
        success: function (data) {
            $('#result').html(data);
        }
    });
});

或者更简单

$.post('@Url.Action("Insert", "Account")', $('#frmRegister').serialize(), function(data) {
    $('#result').html(data);
});

如果您要上传文件,那么您需要使用FormData 并且代码需要是(另请参阅this answer

$('form').submit(function (event) {
    event.preventDefault();
    var formData = new FormData($('#frmRegister').get(0));
    $.ajax({
        type: "POST",
        url: '@Url.Action("Insert", "Account")',
        data: formData,
        processData: false,
        contentType: false,
        datatype: "json",  // refer notes below
        success: function (data) {
            $('#result').html(data);
        }
    });
});

请注意,在将 jQuery 与 FormData 一起使用时,您必须将 processDatacontentType 都设置为 false。

如果你得到一个500(Internal Server Error),它几乎总是意味着你的控制器方法正在抛出一个异常。在您的情况下,我怀疑这是因为您的方法正在返回部分视图(正如您 success 回调中的 $('#result').html(data); 代码行所建议的那样)但您已指定返回类型应为 json (您的使用datatype: "json", 选项)。请注意,不需要指定dataType 选项(如果没有指定.ajax() 方法会解决)

如果这不是500(Internal Server Error) 的原因,那么您需要调试代码以确定导致预期的原因。您可以使用浏览器开发人员工具来协助该过程。打开 Network 选项卡,运行函数,(函数名称将突出显示),单击它,然后检查响应。它将包括所引发的期望的详细信息。

【讨论】:

  • 非常感谢您的精彩解释。我认为这个主题应该像您“上传和不上传文件”一样分为两部分,现在在您的回答的帮助下我完全清楚了。另一方面,我相信这些答案将帮助许多厌倦了寻找有关 AJAX 调用的适当解决方案的人:) 问候...
  • 由于我已经解决了在 MVC 中使用 AJAX 的问题,我将继续对我的 MVC 项目中的所有操作进行 AJAX 调用。您是否建议这样做,或者有什么需要注意的地方?
  • 使用 ajax 的唯一原因是保持在同一页面上。在许多情况下,您可能只想在 POST 方法中进行正常提交并重定向到另一个视图(或者如果 ModelState 无效,则返回该视图)。在您的情况下,您似乎想要保存一些东西,然后用一些额外的数据更新当前页面,在这种情况下,使用 ajax 是合适的。这是初学者使用ajax的常见错误,然后在成功回调中执行location.href='....'重定向(这是没有意义的)
  • 好的,我理解您在上一条评论中强调的要点,即重定向到 AJAX 中的另一个 url 是没有意义的 :) 实际上我已经使用普通提交开发了几个 MVC 应用程序,现在我想做一些页面响应并让用户感受到我的应用程序的速度(当使用 AJAX 操作时似乎要快得多,我也喜欢向用户显示关于上次用户操作发生了什么的警报。所以,我将在我的应用程序只要不需要重定向就可以了 :) 再次感谢您提供这些巨大而有用的信息...
【解决方案2】:

contentType 应该是application/x-www-form-urlencoded

试试这个代码

    <script>
$('form').submit(function (event) {
        event.preventDefault();

    $.ajax({
        method: "POST",
        url: "/Account/Insert",
        data: $(this).serialize(),
       contentType:"application/x-www-form-urlencoded",
        success: function (data) {
       $('#result').html(data);
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(errorThrown);
        }
    });
});
    </script>

【讨论】:

  • "TypeError: FormData.constructor 的参数 1 没有实现接口 HTMLFormElement。" >>> var formData = new FormData($('#frmRegister'));
  • 我已经修改了代码试试这个,让我知道会发生什么。
  • 错了。 contentType 需要设置为 false 才能使 FormData 工作(正如 OP 所做的那样)
  • @StephenMuecke 亲爱的斯蒂芬,为什么不发布一个答案作为 MVC 中使用 Controller 方法的最佳 AJAX 调用的示例?因为你总是给很多人提供完美的答案并教给很多人好的方法:) 我正在等待你的答案,非常感谢......
  • @StephenMuecke 你是个真正的魔法师!再次非常感谢...我在问题的更新部分添加了一些要点。能否请您澄清一下这些问题?
猜你喜欢
  • 2015-07-31
  • 2016-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
  • 2015-07-06
  • 2015-09-26
  • 1970-01-01
相关资源
最近更新 更多