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

Posted

技术标签:

【中文标题】示例 AJAX 回调到 ASP.NET Core Razor 页面【英文标题】:Example AJAX call back to an ASP.NET Core Razor Page 【发布时间】: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 【参考方案1】:

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

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

    注册防伪服务 将令牌添加到您的请求中 通过添加&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。 见:docs.microsoft.com/en-us/aspnet/core/tutorials/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',

【讨论】:

以上是关于示例 AJAX 回调到 ASP.NET Core Razor 页面的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core 模型未通过 AJAX 绑定到控制器

为啥 Asp.net Core 无法读取 Ajax 参数?

CORS 不适用于从 Ajax 到 ASP.NET Core Web API 的调用

ASP.NET Core MVC - 使用 Ajax 将数据发送到另一个模型中的模型

ASP.NET Core MVC - 将 HTML 表转换为 json 并使用 ajax 发送到控制器

在 ASP.Net Core 中使用 AJAX 将复选框列表类的值发送到服务器