Blazor Server 如何跨多个选项卡和刷新保存数据
Posted
技术标签:
【中文标题】Blazor Server 如何跨多个选项卡和刷新保存数据【英文标题】:Blazor Server How to persist data across multiple tabs and refreshes 【发布时间】:2021-08-28 11:51:22 【问题描述】:我正在编写一个需要为用户保存数据的 Blazor Server 应用程序。
我试过以下/以下不符合要求:
会话存储 - 因为它的范围是浏览器选项卡,所以数据会在刷新时消失/而不是在新选项卡上。 本地存储 - 跨多个选项卡和刷新工作,但保留以供将来访问该站点(我不希望数据在多次访问中保留) AppState 方法的范围 - 再次基于每个选项卡的每个电路。我有一些想法,但不确定如何实施/是否是好想法:
使用本地存储,但要么在客户端断开连接时以某种方式清除它,要么在本地存储中添加时间标签,只允许 x 时间的持久性。 可能通过以下方式使用 cookie:Creating and Reading Cookies on Blazor Server Side除此之外,我对如何实现这一点没有任何其他好的想法,因此欢迎任何想法/建议。
【问题讨论】:
使用作用域依赖注入来保存每个电路的状态。 这适用于每个电路,但据我了解,每个选项卡都有一个新的/不同的电路,刷新也可以让你获得一个新的电路——这两个我都需要坚持。 什么是短暂的? Transient 将使其成为对服务器的每个不满足用例的请求的新服务。 如果您有用户身份,那么您可以将数据与数据库(或类似数据库)中的用户相关联,并在任何选项卡甚至不同浏览器上查找。 【参考方案1】:嗯,这不是我原创的,但这是我为登录用户保留租户的方式,只要他们处于连接状态。
public class GlobalService
public event Action<PropertyChangedEventArgs> PropertyChanged;
Subscriber _Tenant;
public Subscriber Tenant
get
return _Tenant;
set
if (!object.Equals(_Tenant, value))
var args = new PropertyChangedEventArgs() Name = "Tenant", NewValue = value, OldValue = _Tenant, IsGlobal = true ;
_Tenant = value;
PropertyChanged?.Invoke(args);
public class PropertyChangedEventArgs
public string Name get; set;
public object NewValue get; set;
public object OldValue get; set;
public bool IsGlobal get; set;
我像这样在 ConfigureServices 中注册它
services.TryAddScoped<GlobalService>();
【讨论】:
【参考方案2】:一种可能的方法是模仿 ASP.net 网络表单的遗留会话变量。这些依赖于没有过期日期的 cookie。 cookie 的生命周期也等于浏览器会话的生命周期。 主要工作是在 _Host.cshtml 中完成,我们将在其中创建一个用作会话标识符的 guid。此 guid 对整个浏览器会话(所有选项卡)都有效。
创建此属性:public Guid NewGuid get; = Guid.NewGuid();
注入 HttpContextAccessor : public HostModel(IHttpContextAccessor httpContextAccessor)
获取cookie值:
string g = httpContextAccessor.HttpContext.Request.Cookies["SessionGuid"] ?? ""; if (Guid.TryParse(g, out Guid guid)) request.SessionGuid = guid; else request.SessionGuid = NewGuid
在此代码中,request 是一个级联参数,将传递给所有组件。
在标记中,您将其添加到正文中
<script>createSessionGuid('@Model.NewGuid');</script>
这使用了这个必须加载的小javascript函数:
function createSessionGuid(newguid)
var current = getCookie("SessionGuid");
if ((current === null) || (current === ""))
var guid = newguid;
document.cookie = "SessionGuid=" + guid + "; path=/";
console.log("SessionGuid created : " + guid);
else
console.log("SessionGuid found : " + current);
通过这种方式,您无需使用 JSInterop 即可获得会话 ID,因此无需使用任何异步代码。
故事的其余部分非常简单:只需创建一个会话类,它是一个字典字典(并发字典)。***字典中的键应该是会话 ID。二级字典中的键就是会话变量名。
编辑:如何在_Host.cshtml中使用CascadingValue?
在_Host.cshtml中:见最后一个参数。
<component type="typeof(App)" render-mode="ServerPrerendered" param-Request="Model.request" />
在 _Host.cshtml 的代码隐藏中
public BaseClasses.Request request;
public HostModel(IHttpContextAccessor httpContextAccessor)
request = new BaseClasses.Request();
httpContextAccessor.HttpContext.Request.Cookies.Where(kvp => kvp.Key != "SessionGuid").ToList().ForEach(kvp => request.Cookies.Add(kvp.Key, kvp.Value));
string g = httpContextAccessor.HttpContext.Request.Cookies["SessionGuid"] ?? "";
if (Guid.TryParse(g, out Guid guid))
request.SessionGuid = guid;
else
request.SessionGuid = NewGuid;
此信息在 MainLayout.razor.cs 中检索并开始级联。
[CascadingParameter]
private BaseClasses.Request Request get; set;
【讨论】:
如何在_Host.cshtml或其后面的代码中使用CascadingValue?我认为您显示的代码说明了这一点。以上是关于Blazor Server 如何跨多个选项卡和刷新保存数据的主要内容,如果未能解决你的问题,请参考以下文章
在刷新页面 MVC 上丢失的 JavaScript 中动态创建的内容
使用 glade 在每个选项卡上设置一个带有选项卡和多个 gtk 输入字段的笔记本
如何从服务器端 Blazor 应用程序中的 Blazor 组件调用 razor 页面而不导致页面刷新