让我们考虑一个简单的 blazor 应用程序(标准模板),其中我需要一些有关已连接用户的信息,例如:
通常,我从 HttpContext 检索此信息。 我特别遵循以下步骤:
builder.Services.AddHttpContextAccessor();
@inject IHttpContextAccessor hca
<p> SessionID: @hca.HttpContext?.Connection?.Id </p>
<p> IP: @hca.HttpContext?.Connection?.RemoteIpAddress </p>
<p> User: @hca.HttpContext?.User?.Identity?.Name </p>
这种方法仍然有效,在 NET6+(使用 NET8)中也是如此,但它被标记为错误,并且在官方指南中不推荐。 (参考 1)(参考 2)
限制 - 如果 LongPolling 传输模式则为 NULL HttpContext
如果传输模式从 WebSockets 回退到 LongPolling,则 HttpContext 为 null。 您可以轻松测试这一点,在启动时强制使用 LongPolling 传输模式
app.MapBlazorHub(opt =>
{
opt.Transports =
//Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets |
Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling;
});
这并不新鲜(参考 3)。
请注意,在某些 Blazor 应用程序上,我被迫使用 LongPolling,因为 WebSocket 在 IIS8 - WinServer2012 之前不受支持和/或被反向代理阻止,由于军团策略而无法更改。
有人使用的另一种方法(也包含在官方指南中)是“在启动时”捕获 HttpContext,然后级联它。
将请求状态传递到 Blazor 应用程序的推荐方法是在应用程序初始渲染期间通过根组件参数
示例此处。看来通过这种方法我们也可以覆盖 LongPolling 的情况。
限制 - 从 js 实例化的单个不可路由 Blazor 组件
现在让我们把情况变得更复杂一些。我有一个 NET8 非 blazor Web 应用程序。我添加了一个从 js 实例化的 不可路由 blazor 组件
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(options =>
{
options.DetailedErrors = true;
options.RootComponents.RegisterForJavaScript<SchedaWeb>(identifier: "scheda-web");
});
Blazor.start()
.then(function () {
Blazor.rootComponents.add(_this.renderScheda[0], 'scheda-web', {
id: id,
})
});
在这种情况下,我没有任何“根组件”:没有应用程序,没有_Host。 无法应用上述解决方案。我应该如何使用 LongPolling 检索 HttpContext?
限制 - HttpContext 不可靠
还有许多其他文章,也在 SignalR 线程(Blazor 所基于的)中,提到了 HttpContext 的不可靠性(参考 4)
根据官方文档,我们应该
对于交互组件中需要 HttpContext 的场景,我们建议通过服务器的持久组件状态来流动数据。有关更多信息,请参阅服务器端 ASP.NET Core Blazor 附加安全方案。
有人可以解释在所有边缘情况下可靠获取 HttpContext 的正确方法是什么(使用 LongPolling 传输模式,将 Blazor 集成在标准应用程序中,无需 root App 或 _Host)?
检查上下文:
public override async Task OnConnectedAsync()
{
await this.hubService.OnHubConnectionAsync(context: Context);
await base.OnConnectedAsync();
}