使用 AJAX 删除 Razor 页面

Razor Pages delete using AJAX

我正在尝试将 AJAX 与 Razor Pages 结合使用。

我一直在网上搜索,但我发现的每个示例都有所不同,而且大多数不完整或不适用于 Razor Pages。

到目前为止,我一直在关注类似这样的变体:

$.post('/?handler=Delete', 5, function (x) {
    alert(x);
});

然后我的页面模型如下所示:

public void OnPostDelete(int id)
{

}

我已经尝试过对此的变体,但到目前为止,我的 C# 代码没有被调用。

问题:

更新:

所以我一直在研究这个,这就是我现在所拥有的:

$.ajax({
    url: '?handler=Delete',
    data: {
        id: $(this).data('id')
    }
})
.fail(function (e) {
    // Error
    alert(e.responseText); // Way too much info
})
.done(function () {
    // Success
})
.always(function () {
    // Always
});

我的经纪人:

public void OnGetDelete(int id)
{

}

这实际上是在调用我的处理程序,我终于让它传递了 id 参数。

由于我有赏金,以下是我希望在答案中看到的内容:

  1. 如果我将 AJAX 调用设置为使用 POST 并将我的处理程序重命名为 OnPostDelete(),则不会调用该处理程序。我该怎么做 post?
  2. 对上述代码还有其他建议或批评吗?我知道有很多方法可以做到这一点。我只是在寻找最简单的方法并尝试改进它。

两条建议:

1-在url前面加上页面路径。 (我不确定你的话里有没有提到)。

$.post('/{page_path}/?handler=Delete', 5, function (x) {
    alert(x);
});

2- 遵循路由映射规则。例如,您的函数中有 'id' 。该页面可能配置为@page "{id:int}"。所以 url 应该是

$.post('/{page_path}/{id}/?handler=Delete', 5, function (x) {
    alert(x);
 });

您可以通过 F12 在“网络”选项卡中检查请求,您可能会看到 400 bad request 错误。

Razor 页面旨在自动保护免受 cross-site 请求伪造 (CSRF/XSRF) 攻击。您不必编写任何额外的代码。防伪令牌生成和验证自动包含在 Razor Pages 中。这里请求失败,页面上没有 AntiForgeryToken。

对于问题,您可以使用 @Html.AntiForgeryToken() 明确添加 要添加 AntiForgeryToken,我们可以使用任何一种方法。这两种方法都添加了一个隐藏的输入类型,名称为 __RequestVerificationToken。 Ajax 请求应将请求 header 中的 anti-forgery 令牌发送到服务器。所以,修改后的 Ajax 请求看起来像

@Html.AntiForgeryToken()

@section Scripts
{
<script>

    $.ajax({
        type: "POST",
        url: "/?handler=Delete&id="+5,
        beforeSend: function (xhr) {
            xhr.setRequestHeader("XSRF-TOKEN",
                $('input:hidden[name="__RequestVerificationToken"]').val());
        },
        success: function (x) {
            alert(x);
        },
        failure: function (response) {
            alert(response);
        }
    });
</script>

}

由于脚本在名为 X-CSRF-TOKEN 的 header 中发送令牌,因此配置防伪服务以查找 X-CSRF-TOKEN header:

public void ConfigureServices(IServiceCollection services)
{
        services.AddRazorPages();
        services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}

参考:https://www.talkingdotnet.com/handle-ajax-requests-in-asp-net-core-razor-pages/

这就是我喜欢的方式:

配置您的 Javascript

//If you're returning a object, configure it
var yourObject = {
    field1: "value1",
    field2: "value2"
};

//setup ajax
$.ajax({
    data: yourObject,
    type: "POST",
    url: "urltoyourhandler/delete" //you can add other paramters here as well by doing ?parm=value
    success: function(data){
      //do success stuff here
      //based off my handler code below:
      if(data.success){
          console.log("Success!");
      }
      else{
          console.log("Failed for some reason!");
      }
    }
    error: function(){
        //do error stuff here
       //gets called if there is a issue contacting the URL or if there is a server error like 500
    }
});

正在配置您的处理程序。对于我的 CRUD 操作,我喜欢制作一个 CRUD 控制器来处理所有事情

[BindProperty]
public YourClass Name { get; set; }

//set handler to only accept POST and set a URL for it. URL should be to the same folder you're in
//the 'delete' in route doesn't have to match the function name but it's less confusing if it does
[HttpPost, Route("RouteToThisHandler/delete)]
public async Task<IActionResult> Delete()
{
    //verify data and the do something with it
    //I like returning a JsonResult. Add whatever data you want. I like returning success 
    //with true or false and some other data if needed
    return new JsonResult(new { success: true, importantInfo: "This is important" });
}

Ajax 有更多配置选项,可为您提供有关发生的任何服务器错误的更多信息

对于防伪令牌,微软表示:

Antiforgery middleware is added to the Dependency injection container when one of the following APIs is called in Startup.ConfigureServices:

  • AddMvc
  • MapRazorPages
  • MapControllerRoute
  • MapBlazorHub

这里是微软link关于防伪令牌的:https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-3.1

我调查了一些事情,当你从 AJAX 传递一个字符串而不是一个整数时会发生什么,以及不同的路由如何影响调用(如果你有时间,请参阅下面有趣的注释)但主要是,我所发现的只是 Razor Pages 相当宽容,一切似乎都能正常工作。就像我提到的,即使传递一个字符串,其中整数类型 id 仍然命中处理程序方法(它只是给了我一个 default(int)

我创建这个 repo 只是为了探索:https://github.com/EntityAdam/RazorPageHandlers

正如@Yan 指出的那样,主要的障碍是防伪令牌。这确实是导致处理程序未命中断点的唯一原因。正如建议的那样,检查您的网络选项卡是否有失败的请求或控制台是否有错误 JavaScript 代码。

从您的代码片段中,要将其更改为 OnPostDelete,您需要在 AJAX 调用中使用 POST 类型并包含防伪标记。

$.ajax({
    type: 'POST',
    headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
    url: '?handler=Delete',
    data: {
        id: $(this).data('id')
    }
})
.fail(function (e) {
    // Error
    alert(e.responseText); // Way too much info
})
.done(function () {
    // Success
})
.always(function () {
    // Always
});

另一个我没有看到讨论的话题是这个令牌来自哪里?只要有 <form> 元素,它就会由 Razor 自动生成。如果您没有 <form> 元素,您可以在需要时生成标记,查看此 MSDN Article 中的 @functions {} 块。在某些情况下,CSRF 无用或不需要,如果不需要,您也可以关闭防伪造(这是一个完全不同的讨论)。

我对这种方法的批评是意见,所以要么接受要么放弃。

  • 如果可以避免使用 jQuery,前提是 JavaScript 的改进可以说已经过时 jQuery。使用普通的 JS 代码。
  • Ajax 也显示了它的年龄。如果您只需要支持现代浏览器,请考虑 Fetch API
  • 完全不写任何JS! Blazor 是新的,闪亮的。仍然有一些成长的烦恼,但我宁愿我的痛苦在 C# 中而不是在 JavaScript =)

我遇到的一件有趣的事..

对于这个演示,我使用了以下 @page 指令

@page "{id?}"

在 HTML 部分的表格如:

<form method="post" asp-page-handler="Delete">
    <input type="hidden" name="id" value="1" />
    <button class="btn btn-danger">Delete</button>
</form>

我正在使用 asp-page-handler 标签助手来帮助生成正确的 URL。对于 Create 处理程序,使用 @page 指令,标签助手提出了 /?handler=Create

的表单目标

如果您用 @page "{handler?}/{id:int?}" 替换掉 @page 指令,标签助手会计算出现在的路由 /Delete。但猜猜怎么了? AJAX 调用与任一 @page 指令一起工作,即使 AJAX 中的 URL 被硬编码为 ?handler=Delete'