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



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

我目前使用的是Blazor Server .net 6。我已经尝试从"serverpreendered"更改渲染模式。到"服务器",但这并不能解决问题。将呈现模式更改为"静态";确实阻止了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类,我用它来捕获表单数据。它使用了一个PostFormService,它是一个有作用域的服务,只有一个属性包含Form数据。将其更改为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;
}
}
}

我读取form-data的razor页面:

@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,html中向App.razor传递参数:

@(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实例在任何地方消耗它。

最新更新