如何在 Blazor 页面中使用从 POST 请求收到的表单数据?

How to use Form data received from a POST request in Blazor pages?

我有一个 Blazor 页面,可以从 POST 请求接收表单数据。接收到此数据后,它会被设置为两个属性并同时呈现到页面上。问题是发生这种情况后,页面将重新呈现并且属性的数据将被丢弃。 有人知道为什么会这样吗?最好的方法是保留我的 POST 数据,或者阻止页面重新呈现?

我目前正在使用 Blazor Server .net 6。我已经尝试将渲染模式从“ServerPrerendered”更改为“Server”,但这并没有解决问题。将呈现模式更改为“静态”确实会阻止 Blazor 重新呈现页面,但我不想拥有静态页面。

这是我的 _Host.cshtml:

@page "/"
@namespace PostToRazorPageTest.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = "_Layout";
}

<component type="typeof(App)" render-mode="ServerPrerendered" />

@attribute [IgnoreAntiforgeryToken]

@model HostPageModel

在这里您可以看到我用来捕获表单数据的 HostPageModel class。它使用 PostFormService,这是一个范围服务,其中一个 属性 包含表单数据。改成Singleton确实可以防止POST数据被丢弃,但也会形成很大的隐私风险。

using Microsoft.AspNetCore.Mvc.RazorPages;
using PostToRazorPageTest.Services;

namespace PostToRazorPageTest.Pages
{
    public class HostPageModel : PageModel
    {
        // postFormService is injected by the DI
        public HostPageModel(PostFormService postFormService)
        {
            PostFormService = postFormService;
        }

        private PostFormService PostFormService { get; }

        public void OnPost()
        {
            // store the post form in the PostFormService
            PostFormService.Form = Request.Form;
        }

    }
}

我读取表单数据的剃刀页面:

@page "/showdata"
@inject PostFormService PostFormService;

<PageTitle>Show POST data</PageTitle>

<h1>Show POST data</h1>

@if (Field1 != null && Field2 != null)
{
    <p>Field 1 value: @Field1</p>
    <p>Field 2 value: @Field2</p>
}
else
{
    <p>
        <b>
        The request wasn't made with a POST request, or the request was missing data for the field called "field1" and/or "field2".
        </b>
    </p>
}

@code {
    private string? Field1 { get; set; }
    private string? Field2 { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        if (PostFormService.Form != null)
        {
            Field1 = PostFormService.Form["field1"];
            Field2 = PostFormService.Form["field2"];
        }
    }
}

这是评论而不是完整的答案:我不能将示例代码放入评论中!

您可以对您的服务执行类似的操作以使请求唯一,然后将 Guid - 可能作为字符串传递到 App

public class DataService
{
    private Dictionary<Guid, FormData> _formData = new Dictionary<Guid, FormData>(); 

    public Guid AddFormData(FormData data)
    {
        var id = Guid.NewGuid();
        _formData.Add(id, data);
        this.ClearData();
        return id;
    }

    public bool TryGetFormData(Guid guid, out FormData data)
    {
        data = _formData[guid];
        this.ClearData();
        return data != null;
    }
    
    // clears old data
    private void ClearData()
    {
        var list = _formData.Where(item => item.Value.TimeStamp.AddMinutes(5) <= DateTime.Now).ToList();
        list.ForEach(item => _formData.Remove(item.Key));
    }

}

// example form data class
public class FormData
{
    public string Name { get; set; } = string.Empty;

    public DateTime TimeStamp { get; } = DateTime.Now;
}

您可以将参数传递到 _Host 中的 App.razor,html,如下所示:

@(await Html.RenderComponentAsync<BlazorApp2.App>( RenderMode.ServerPrerendered,new {FormGuid="1234"}))
@*<component type="typeof(App)" render-mode="ServerPrerendered" />*@

然后您可以使用范围服务来保存表单数据:

// Set up as Scoped i.e. one per user session
public class MyFormDataService
{
    private readonly DataService dataService;

    public FormData? FormData { get; private set }

    public MyFormDataService(DataService dataService)
        => this.dataService = dataService;

    public void GetFormData(Guid id)
    {
        if (dataService.TryGetFormData(id, out FormData data))
            this.FormData = data;
    }
}

并加载 App

中的服务
@inject MyFormDataService dataService
<div>@this.FormGuid</div>
<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code{
    [Parameter] public Guid FormGuid { get; set; }

    protected override void OnInitialized()
        =>  this.dataService.GetFormData(FormGuid);
}

并通过注入 MyFormDataService 的 DI 实例在任何地方使用它。