如何在 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 实例在任何地方使用它。
我有一个 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 实例在任何地方使用它。