【问题标题】:Example AJAX call back to an ASP.NET Core Razor Page示例 AJAX 回调到 ASP.NET Core Razor 页面
【发布时间】:2018-03-06 17:57:39
【问题描述】:

我发现一个页面上有多个处理程序以及相关的命名约定(即 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("");
    }
}

OnPost 不是从 Ajax 调用中调用的。

【问题讨论】:

  • 你想做什么?你能展示你的观点吗?
  • 没有“视图”,只有 Razor 页面。我已经扩展了这个例子。
  • docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/… @page 使文件成为 MVC 操作 - 这意味着它直接处理请求,而不通过控制器。 ... URL 路径与页面的关联取决于页面在文件系统中的位置。下表显示了 Razor 页面路径和匹配 URL:文件名和路径匹配 URL /Pages/Index.cshtml / 或 /Index /Pages/Contact.cshtml /Contact /Pages/Store/Contact.cshtml /Store/Contact / Pages/Store/Index.cshtml /Store 或 /Store/Index

标签: c# ajax asp.net-core-2.0 razor-pages


【解决方案1】:

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

要解决这个问题,您必须:

  1. 注册防伪服务
  2. 将令牌添加到您的请求中
  3. 通过添加&lt;form&gt; 或直接使用@Html.AntiForgeryToken HtmlHelper 将防伪令牌添加到您的页面

1。在您的Startup.cs 中注册防伪服务

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

2。修改你的 AJAX 回调

在 AJAX 回调中,我们添加了额外的代码来发送带有请求标头的 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。将防伪令牌添加到您的页面

您可以通过添加&lt;form&gt; 来完成此操作:

<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" />

【讨论】:

  • 我遇到了同样的问题。如果您查看控制台输出,它会告诉您缺少 XSRF-TOKEN。
  • 即使进行了这些更改,我仍然收到错误请求。该文档docs.microsoft.com/en-us/aspnet/core/security/… 谈到了进行类似的更改,但这似乎也不起作用:(
  • 你重建了吗?我完全按照我写的方式进行了测试,并开始收到回复。还要确保 program.cs 使用 Microsoft.Extensions.DependencyInjection;
  • 刚刚创建了一个新的网络应用程序并根据我的 OP 修改了“关于”页面(还添加了一个错误处理程序,见上文)和您建议的更改。控制台显示以下内容:状态:错误错误请求。这似乎是正确的道路,但我只是错过了一些东西。
  • 无需添加 [ValidateAntiForgeryToken] 属性,因为 Razor 页面旨在自动验证 Antiforgery 令牌。
【解决方案2】:

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

URL 路径与页面的关联取决于页面在文件系统中的位置。下表显示了 Razor 页面路径和匹配的 URL

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

/Pages/Contact.cshtml 映射到 /Contact

【讨论】:

  • 我了解页面的路径,但 AJAX 调用未触发 OnPost 方法。你有一个有效的 ajax 调用的例子吗?
  • 您是否收到错误请求或未找到?
  • @Greg regaring Url,最好使用@Url.Page让asp.net构造正确的url并传递参数。
【解决方案3】:

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

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',

【讨论】:

  • 刚刚测试了这个与接受的答案相比,它似乎不起作用。您是否使用新的 Razor Pages 而不是 MVC 进行了测试? url应该指向页面,
  • 我通过VS2017创建了一个新项目“Asp.net Core 2.0”并修改了View About。我还没有创建新的 Controller,url 指向包含 Home 视图的文件夹。启动应用程序后,通过浏览器的调试(F12 键),网络 -> 您可以在“onPost”中看到正确答案。
  • 您正在创建一个 MVC Web 应用程序。不是 Razor Page 网络应用程序。 About 应该在 Pages 文件夹下而不是 View 下。我确定您所做的对 MVC 来说很好,但它不适用于 Razor Pages。
  • 你是对的。事实上,我正在“Asp.net Core 2”类型的 Web 应用程序 MVC 中创建一个应用程序,它可以工作。
【解决方案4】:

查看上面的答案后,我使用 Visual Studio 2017 Preview 2 获得了 JSON ajax 来处理 .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

【讨论】:

    【解决方案5】:

    接受的解决方案在本地开发机器上工作,但失败然后部署在 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 Razor 页面; jQuery 3.3.1

    【讨论】:

      【解决方案6】:

      以下内容适用于使用 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 });
          }
      

      【讨论】:

        【解决方案7】:

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

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

        不再需要防伪令牌。

        【讨论】:

          【解决方案8】:

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

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

          那么我们应该在 url 中指定处理程序名称:

          url: 'OnPost?handler=filter1',
          

          【讨论】:

            猜你喜欢
            • 2018-09-04
            • 2020-02-09
            • 2019-08-04
            • 2018-12-20
            • 1970-01-01
            • 2020-08-22
            • 2021-06-26
            • 2019-03-12
            • 2021-10-27
            相关资源
            最近更新 更多