Receiving share data from Web Share API using POST in Blazor 8 Pages and binding request formData into parameters

101 Views Asked by At

I have a PWA Webapplication that was previously only in ASPNet Core MVC and I am now conevrting it to Blazor 8.

I am consuming shared data that is invoked outside of the app with the Web Share API. This worked perfectly in the MVC app and can receive shared text, urls, files etc. In Blazor, however, it only works with the GET method. The POST method fails due to either AntiforgeryToken not present or formData not binding

The GET method is ok for just normal text and url's but I need the POST method to enable file shares as well.

But I cannot get the formData bound to the Blazor page.

MVC Option

In MVC this works for both GET and POST because [ValidateAntiForgeryToken] is not specified and is therefore not required.

MVC Controller

    public class ShareController : Controller
    {
        public IActionResult MVCShareFromGet([FromQuery] string url, [FromQuery] string title)
        {
            return View("MVCShare", new Sharemodel(url, title));
        }
        public IActionResult MVCShareFromPost([FromForm] string url, [FromForm] string title)
        {
            return View("MVCShare", new Sharemodel(url, title));
        }

For the POST method the properties are bound by [FromForm] whereas in the GET method it is [FromQuery]

MVCView:

@model DataCoord.Sharemodel
<p>Title: @Model.title</p>
<p>Url: @Model.url</p>

Blazor Option

In Blazor SSR Antiforgery is setup by default. Therefore in GET methods, it works, but with POST methods will fail. Manifest:

    "action": "/BlazorShareGet", 
    "method": "GET", 
    "params": {
      "title": "title",
      "text": "text",
      "url": "url"
      ...

Blazor Page:

@page "/BlazorShareGet" 
<p>Shared title: @title</p>
<p>Shared url: @url</p> 
@code { 
    [SupplyParameterFromQuery]
    string? title { get; set; }
    [SupplyParameterFromQuery]
    string? url { get; set; }
}

Manifest:

    "action": "/BlazorSharePost", 
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "title": "title",
      "text": "text",
      "url": "url"
      ...

Blazor Page:

@page "/BlazorSharePost"
<p>Shared title: @title</p>
<p>Shared url: @url</p>
@code {
    [SupplyParameterFromForm]
    string? title { get; set; }
    [SupplyParameterFromForm]
    string? url { get; set; }
}

For the `POST` method the I try to bind the formData by `[SupplyParameterFromForm]` ???? but not sure if this is correct, whereas in the `GET` method it is `[SupplyParameterFromQuery]` which works.

I get the following ERROR:

A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint.

When I disable antiforgery entirely

app.MapRazorComponents<App>()
    .DisableAntiforgery()
    .AddInteractiveServerRenderMode()

I get

The POST request does not specify which form is being submitted. To fix this, ensure <form> elements have a @formname attribute with any unique value, or pass a FormName parameter if using <EditForm>.

I also tried [SupplyParameterFromForm], [SupplyParameterFromQuery], [Parameter], [CascadingParameter]

Note I don't have control over the request as it comes from third party / browser

Examining the request there is a matching matching .AspNetCore.Antiforgery Cookie present

Question

  1. How to disable antiforgery validation for this endpoint only?
  2. How to bind posted formData into Blazor Page
1

There are 1 best solutions below

0
Fengzhi Zhou On

In my test adding this on the pagemodel, that is to do in a specific page handler way, is still controlled by the global filter. For a Blazor page, you can disable the antiforgery token through a specific action method using [IgnoreAntiforgeryToken].

[ApiController]
[Route("[controller]")]
public class BlazorController : ControllerBase
{

    [HttpPost("BlazorPost")]
    [IgnoreAntiforgeryToken]
    public IActionResult BlazorPost([FromForm] string title, [FromForm] string url)
    {
        ...
        return Ok(new { title, url });
    }
}

enter image description here

Binding post data to Blazor page properties is not the typical use case since Blazor operates differently. You would typically handle form submission using C# methods and edit components with model binding.