AJAX 回调到 ASP.NET Core Razor 页面的示例

Example AJAX call back to an ASP.NET Core Razor Page

我找到了在一个页面上有多个处理程序以及关联的命名约定(即 OnPostXXX)和 'asp-post-hanlder' 标签助手的示例。但是如何从 AJAX 调用中调用这些方法之一。

我有一个带有典型 MVC 视图和控制器的旧示例,但它如何与 Razor 页面一起使用?

例如,如果我使用基本应用程序并将 About.cshtml 页面修改为以下内容:

@page
@model AboutModel
@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@Model.Message</h3>

    <input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();"  />

@section Scripts {
<script type="text/javascript">
    function ajaxTest() {
        console.log("Entered method");
        $.ajax({
            type: "POST",
            url: '/About', // <-- Where should this point?
            contentType: "application/json; charset=utf-8",
            dataType: "json",
        error: function (xhr, status, errorThrown) {
            var err = "Status: " + status + " " + errorThrown;
            console.log(err);
        }
        }).done(function (data) {
            console.log(data.result);
        })
    }
</script>
}

并在模型页面上 About.cshtml.cs

public class AboutModel : PageModel
{
    public string Message { get; set; }

    public void OnGet()
    {
        Message = "Your application description page.";
    }

    public IActionResult OnPost() {
        //throw new Exception("stop");
        return new JsonResult("");
    }
}

Ajax 调用未调用 OnPost。

请参阅文档的相关部分 https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=visual-studio

The associations of URL paths to pages are determined by the page's location in the file system. The following table shows a Razor Page path and the matching URL

/Pages/Index.cshtml 映射到 / 或 /Index

/Pages/Contact.cshtml 映射到 /Contact

Razor Pages 自动生成并验证防伪令牌以防止 CSRF 攻击。由于您没有在 AJAX 回调中发送任何令牌,因此请求失败。

要解决此问题,您必须:

  1. 注册Antiforgery-Service
  2. 将令牌添加到您的请求中
  3. 通过添加 <form> 或直接使用 @Html.AntiForgeryToken HtmlHelper
  4. 将防伪令牌添加到您的页面

1。在 Startup.cs

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

2。修改您的 AJAX 回调

在 AJAX 回调中,我们添加了额外的代码以通过我们的请求 header.

发送 XSRF-TOKEN
$.ajax({
    type: "POST",
    url: '/?handler=YOUR_CUSTOM_HANDLER', // Replace YOUR_CUSTOM_HANDLER with your handler.
    contentType: "application/json; charset=utf-8",

    beforeSend: function (xhr) {
      xhr.setRequestHeader("XSRF-TOKEN",
        $('input:hidden[name="__RequestVerificationToken"]').val());
    },

    dataType: "json"
}).done(function (data) {
  console.log(data.result);
})

3。将防伪令牌添加到您的页面

您可以通过添加 <form>:

来完成此操作
<form method="post">
    <input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>

或使用 @Html.AntiForgeryToken:

@Html.AntiForgeryToken()
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />

在这两种情况下,Razor Pages 都会在页面加载后自动添加包含防伪标记的隐藏输入字段:

<input name="__RequestVerificationToken" type="hidden" value="THE_TOKEN_VALUE" />

一切正常,但必须进行一些更改:

1)打开Startup.cs:

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

2)打开HomeController.cs:

[ValidateAntiForgeryToken]
        public IActionResult OnPost()
        {
            return new JsonResult("Hello Response Back");
        }

3)打开About.cshtml:

@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>

<p>Use this area to provide additional information.</p>
<form method="post">
    <input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>

<script type="text/javascript">
    function ajaxTest() {
        $.ajax({
            type: "POST",
            url: 'onPost',
            contentType: "application/json; charset=utf-8",
            beforeSend: function (xhr) {
                xhr.setRequestHeader("XSRF-TOKEN",
                    $('input:hidden[name="__RequestVerificationToken"]').val());
            },
            dataType: "json"
        }).done(function (data) {
            console.log(data.result);
        })
    }
</script>

需要注意的是,控制器内部添加了"onPost",所以在AJAX中应该注明正确的"url"。那么:

url: 'onPost',

答案对我有用。如果我们在页面上有自定义方法,我只会补充说:

   public IActionResult OnPostFilter1()
    {
        return new JsonResult("Hello Response Back");
    }

然后我们应该在 url:

中指定处理程序名称
url: 'OnPost?handler=filter1',

看了上面的答案后,我 JSON ajax 使用 Visual Studio 2017 预览版 2 来处理 .NET Core 2.1 Razor 页面:

Startup.cs

services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");

PostJson.cshtml

@page
@model myProj.Pages.PostJsonModel
@{
    ViewData["Title"] = "PostJson";
}

<input type="button" value="Post Json" class="btn btn-default" onclick="postJson();" />

<script>
    function ajaxRazorPostJson(o) {
        return $.ajax({
            type: "POST",
            data: JSON.stringify(o),
            url: 'postJson',
            contentType: "application/json; charset=utf-8",
            beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); },
            dataType: "json"
        });
    }

    function postJson() {
        ajaxRazorPostJson({ reqKey: "reqVal" }).done(data => alert(data));
    }
</script>

PostJson.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json.Linq;    

namespace myProj.Pages
{
    public class PostJsonModel : PageModel
    {
        public IActionResult OnPost([FromBody] JObject jobject)
        {
            // request buffer in jobject
            return new ContentResult { Content = "{ \"resKey\": \"resVal\" }", ContentType = "application/json" };
            // or ie return new JsonResult(obj);
        }
    }
}

浏览器

http://localhost:44322/postJson

接受的解决方案在本地开发机器上有效,但在 Nginx 反向代理后面的 Debian 服务器上部署失败(未找到 404 错误)。

这是一个有效载荷数据的工作示例:

<script type="text/javascript">
    $('#btnPost').on('click', function () {

        var payloadData; /*asign payload data here */

        $.post({              /* method name in code behind, and full path to my view*/
            url: '@Url.Action("OnPostAsync", "/Turtas/Inventorius/InventoriausValdymas")', 
            beforeSend: function (xhr) {
                xhr.setRequestHeader("XSRF-TOKEN",
                    $('input:hidden[name="__RequestVerificationToken"]').val());
            },
            data: JSON.stringify({ payloadData }),
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        })
    })
</script>

VS 2017; .Net Core 2.2 剃刀页面; jQuery3.3.1

以下使用 headers 设置与 ASP.NET Core MVC 3.1 一起使用:

$.ajax({
    type: "POST",
    url: '/Controller/Action', 
    data: {
        id: 'value'
    },
    headers: {
        RequestVerificationToken:
            $('input:hidden[name="__RequestVerificationToken"]').val()
    },
    error: function (xhr, status, errorThrown) {
        var err = "Error: " + status + " " + errorThrown;
        console.log(err);
    }
}).done(function (data) {
    console.log(data.result);
});

在控制器方法中包含 ValidateAntiForgeryToken 属性:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<JsonResult> Action(string id)
    {
        var result = $"You sent '{id}'";
        return Json(new { id, result });
    }

我为后代添加这个。 争论同样的问题,我发现以下代码可以添加到 Startup.cs:

services.AddRazorPages().AddRazorPagesOptions(options =>
{
    options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
});

不再需要防伪令牌。